Skip to content

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

Merged
merged 1 commit into from
Aug 31, 2017
Merged

Conversation

CodaFi
Copy link
Contributor

@CodaFi CodaFi commented Aug 24, 2017

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.

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 24, 2017

@swift-ci please test

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 24, 2017

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.

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 3e41c5602ff33c33809783c6e7b2a8df8b78ffe6

@@ -43,6 +43,8 @@ namespace swift {
Endianness,
/// Runtime support (_ObjC or _Native)
Runtime,
/// Conditional import
CanImport,
};
enum { NumPlatformConditionKind = 4 };
Copy link
Member

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)

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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.

@@ -98,6 +98,10 @@ checkPlatformConditionSupported(PlatformConditionKind Kind, StringRef Value,
case PlatformConditionKind::Runtime:
return contains(SupportedConditionalCompilationRuntimes, Value,
suggestions);
case PlatformConditionKind::CanImport:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indent

@CodaFi CodaFi force-pushed the refined-imported-goods branch 3 times, most recently from 8b7343b to f39eb16 Compare August 25, 2017 07:17
@@ -332,8 +333,7 @@ namespace swift {
}

private:
llvm::SmallVector<std::pair<PlatformConditionKind, std::string>,
NumPlatformConditionKind>
llvm::SmallVector<std::pair<PlatformConditionKind, std::string>, 4>
Copy link
Contributor

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...

Copy link
Contributor Author

@CodaFi CodaFi Aug 25, 2017

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.

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 25, 2017

@harlanhaskins Does not doing condition resolution in parse-only passes affect libSyntax at all?

@CodaFi CodaFi force-pushed the refined-imported-goods branch from f39eb16 to 50de421 Compare August 25, 2017 21:01
@CodaFi CodaFi changed the title [WIP] Implement SE-0075: CanImport Implement SE-0075: CanImport Aug 25, 2017
@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 26, 2017

@swift-ci test

Copy link
Contributor

@benlangmuir benlangmuir left a 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 canImports during rename.

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 28, 2017

@benlangmuir So then, what's the best way to detect that in a parse-only pass?

@benlangmuir
Copy link
Contributor

@CodaFi Could we rename yourParseOnly bit to something like ShouldEvaluateIfConfigConditions and set it explicitly in the rename code?

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 28, 2017

I will add a flag to performParseOnly as a stopgap, but we have to plan for a future where evaluation occurs in a later phase.

@CodaFi CodaFi force-pushed the refined-imported-goods branch from 50de421 to a88af81 Compare August 28, 2017 22:34
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.
@CodaFi CodaFi force-pushed the refined-imported-goods branch from a88af81 to 75a83da Compare August 28, 2017 22:35
@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 28, 2017

@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);
Copy link
Contributor Author

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.

Copy link
Contributor

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.

@benlangmuir
Copy link
Contributor

benlangmuir commented Aug 29, 2017

I will add a flag to performParseOnly as a stopgap, but we have to plan for a future where evaluation occurs in a later phase.

@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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this testable?

Copy link
Contributor Author

@CodaFi CodaFi Aug 29, 2017

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).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, just checking.

Copy link
Contributor

@benlangmuir benlangmuir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 29, 2017

@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.

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 29, 2017

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.

@benlangmuir
Copy link
Contributor

@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.

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 29, 2017

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.

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 29, 2017

Or if we start from a distinguished syntactic tree, whatever the reverse of the LegacyASTTransformer is could resolve these conditions

@benlangmuir
Copy link
Contributor

@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.

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 31, 2017

@swift-ci please test and merge

@CodaFi
Copy link
Contributor Author

CodaFi commented Aug 31, 2017

Failures are definitely unrelated.

@swift-ci please smoke test and merge

@swift-ci swift-ci merged commit fa76c56 into swiftlang:master Aug 31, 2017
@CodaFi CodaFi deleted the refined-imported-goods branch August 31, 2017 04:29
benrimmington added a commit to swiftlang/swift-evolution that referenced this pull request Sep 3, 2017
@jrose-apple
Copy link
Contributor

Mentioning this as rdar://problem/27382987 to hopefully help Apple's automated systems to track the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants