Hi everyone!
Recently I have often run into SR-4079, so I decided to use this as interesting task to make first contribution to swift and get a little compiler practice.
Firstly I ran swift -dump-ast
on simple enum with availability attributes on cases
enum SomeEnum {
case unrestricted
@available(OSX 10.52, *)
case availableOn1052
@available(OSX 10.53, *)
case availableOn1053
var availableVersion: Int? {
switch self {
case .unrestricted:
return nil
case .availableOn1052:
return 1052
case .availableOn1053:
return 1053
}
}
}
and found the following important part for my task:
(case_stmt range=...
(case_label_item
(pattern_enum_element type='SomeEnum' SomeEnum.unrestricted))
I looked through CaseStmt
class and located getPattern()
method with EnumElementPattern
subclass. Using that classes I added minimal method buildCaseStmtRefinementContext
to TypeRefinementContextBuilder
:
void buildCaseStmtRefinementContext(CaseStmt *CS) {
Optional<AvailabilityContext> BodyRange = None;
for (const auto &caseItem : CS->getCaseLabelItems()) {
auto *elementPattern = dyn_cast<EnumElementPattern>(caseItem.getPattern());
if (!elementPattern)
continue;
auto *D = elementPattern->getElementDecl();
if (!hasActiveAvailableAttribute(D, Context))
continue;
AvailabilityContext ElementInfo =
swift::AvailabilityInference::availableRange(D, Context);
if (BodyRange.hasValue()) {
BodyRange.getValue().constrainWith(ElementInfo);
} else {
BodyRange = ElementInfo;
}
}
if (BodyRange.hasValue()) {
// Create a new context for the body and traverse it in the new
// context.
auto *BodyTRC = TypeRefinementContext::createForCaseStmtBody(
Context, CS, getCurrentTRC(), BodyRange.getValue());
TypeRefinementContextBuilder(BodyTRC, Context).build(CS->getBody());
} else {
build(CS->getBody());
}
}
After compiling the compiler the problem remained in place, therefore I had to dig deeper. Two hours of debugging led me to TypeCheckSourceFileRequest
where availability refinement context builds before type checking decls. CS->dump()
outputs
(pattern_expr
(unresolved_member_expr type='<null>' name='unrestricted' arg_labels=))
I can't get original enum case decl with attributes from unresolved_member_expr
. In ideal world there is API for partial typechecking before the full one, and I suspect swift has one, but I don't know how to use it :(