-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Implement SE-0075: CanImport #11613
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement SE-0075: CanImport #11613
Conversation
@swift-ci please test |
Longer-term answers to this would involve pushing condition resolution further down into the stack. But we currently don't have a strong phase separation between name binding and parse. |
Build failed |
include/swift/Basic/LangOptions.h
Outdated
@@ -43,6 +43,8 @@ namespace swift { | |||
Endianness, | |||
/// Runtime support (_ObjC or _Native) | |||
Runtime, | |||
/// Conditional import | |||
CanImport, | |||
}; | |||
enum { NumPlatformConditionKind = 4 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add comments about why NumPlatformConditionKind
does not count CanImport
?
Or increment this, and update PlatformConditionValues
declaration with NumPlatformConditionKind - 1
(with comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is having NumPlatformConditionKind
defined in the first place really necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessary, but I added this in 1f3c6622#diff-f544d77b7be49d30361f0f41d9f38244L275 because people forget to update this value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking is that even if people update this value, it's better to provide recommended bounds in powers of two.
lib/Basic/LangOptions.cpp
Outdated
@@ -98,6 +98,10 @@ checkPlatformConditionSupported(PlatformConditionKind Kind, StringRef Value, | |||
case PlatformConditionKind::Runtime: | |||
return contains(SupportedConditionalCompilationRuntimes, Value, | |||
suggestions); | |||
case PlatformConditionKind::CanImport: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: indent
8b7343b
to
f39eb16
Compare
@@ -332,8 +333,7 @@ namespace swift { | |||
} | |||
|
|||
private: | |||
llvm::SmallVector<std::pair<PlatformConditionKind, std::string>, | |||
NumPlatformConditionKind> | |||
llvm::SmallVector<std::pair<PlatformConditionKind, std::string>, 4> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit unfortunate to lose the named constant here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, but I'm not really sure what it buys us outside of this one place.
@harlanhaskins Does not doing condition resolution in parse-only passes affect libSyntax at all? |
f39eb16
to
50de421
Compare
@swift-ci test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're going to have to do something slightly different for syntactic rename. Syntactic rename is "parse-only", but we do want to resolve #if
conditions accurately, and are passing in command-line arguments so that we can do that. I'm fine with hitting the disk for any canImport
s during rename.
@benlangmuir So then, what's the best way to detect that in a parse-only pass? |
@CodaFi Could we rename your |
I will add a flag to |
50de421
to
a88af81
Compare
This implementation required a compromise between parser performance and AST structuring. On the one hand, Parse must be fast in order to keep things in the IDE zippy, on the other we must hit the disk to properly resolve 'canImport' conditions and inject members of the active clause into the AST. Additionally, a Parse-only pass may not provide platform-specific information to the compiler invocation and so may mistakenly activate or de-activate branches in the if-configuration decl. The compromise is to perform condition evaluation only when continuing on to semantic analysis. This keeps the parser quick and avoids the unpacking that parse does for active conditions while still retaining the ability to see through to an active condition when we know we're moving on to semantic analysis anyways.
a88af81
to
75a83da
Compare
@swift-ci please smoke test |
@@ -1366,7 +1366,7 @@ SourceFile *SwiftLangSupport::getSyntacticSourceFile( | |||
Error = "Compiler invocation set up failed"; | |||
return nullptr; | |||
} | |||
ParseCI.performParseOnly(); | |||
ParseCI.performParseOnly(/*EvaluateConditionals*/true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benlangmuir Is this correct? Should this be a parameter to this function? Its callers are the 'syntactic rename' and the 'find rename ranges' actions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a fine stopgap to me.
@CodaFi just to clarify: when you say "in a later phase", will this be something we can run independently of sema/type-checking? That's going to be a requirement for syntactic rename. |
@@ -331,6 +332,8 @@ class ValidateIfConfigCondition : | |||
DiagName = "architecture"; break; | |||
case PlatformConditionKind::Endianness: | |||
DiagName = "endianness"; break; | |||
case PlatformConditionKind::CanImport: | |||
DiagName = "import conditional"; break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this testable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of now, no. There's no validation of the module name being performed, so there's no way this will get hit (see the FIXME).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, just checking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@benlangmuir I originally wanted to do this in name binding but now I think making the configurations a kind of DeclContext and teaching lookup about how to properly find these is the right way to model the problem. If Syntactic Rename needs this, and the cost of hitting the disk isn't a problem, would it be possible to use the semantic tree instead? Evaluating conditions in the AST is a bona-fide semantic operation that doesn't belong in Parse. |
An option might be to have this notion of the "name bound tree" for the point at which the AST is well-formed syntactically and has gone through condition resolution and name binding but has not yet been typechecked. |
@CodaFi why do we need to conflate if-config condition evaluation with name binding? We don't need name-binding to evaluate the conditions, right? It seems like what we want for syntactic rename is to walk the syntax tree but evaluate and track the if-config context as we go. |
Because condition resolution can introduce arbitrary names into scopes. That requires re-binding declrefs that are currently being eagerly bound by Parse. Currently, that's how Syntactic Rename is even finding these names: Parse is hoisting the active set of declarations and statements into the right scope and then binding them later on which is strange because it means our parser has its own understanding of scope. My idea, post ASTScope, is to scrap all of that and teach lookup to walk through these conditions. |
Or if we start from a distinguished syntactic tree, whatever the reverse of the LegacyASTTransformer is could resolve these conditions |
@CodaFi syntactic rename shouldn't need name binding in theory. It gets its list of locations from the indexer not by looking at the AST. We only parse so that we can figure out argument labels, determine active-vs-inactive, etc. If parsing no longer puts active code into scopes or no longer binds names itself then I think we should adapt to that rather than require name binding. CC @nathawes in case I'm missing something. |
@swift-ci please test and merge |
Failures are definitely unrelated. @swift-ci please smoke test and merge |
Mentioning this as rdar://problem/27382987 to hopefully help Apple's automated systems to track the PR. |
This implementation required a compromise between parser
performance and AST structuring. On the one hand, Parse
must be fast in order to keep things in the IDE zippy, on
the other we must hit the disk to properly resolve 'canImport'
conditions and inject members of the active clause into the AST.
Additionally, a Parse-only pass may not provide platform-specific
information to the compiler invocation and so may mistakenly
activate or de-activate branches in the if-configuration decl.
The compromise is to perform condition evaluation only when
continuing on to semantic analysis. This keeps the parser quick
and avoids the odd unpacking that parse does for active conditions
while still retaining the ability to see through to an active
condition when we know we're moving on to a more expensive phase like
semantic analysis anyways.
Resolves SR-1560 and any associated shadowing oddities from the first go around.