File tree 4 files changed +83
-4
lines changed
4 files changed +83
-4
lines changed Original file line number Diff line number Diff line change @@ -4744,6 +4744,25 @@ class KeyPathExpr : public Expr {
4744
4744
return getKind () != Kind::Invalid;
4745
4745
}
4746
4746
4747
+ bool isResolved () const {
4748
+ if (!getComponentType ())
4749
+ return false ;
4750
+
4751
+ switch (getKind ()) {
4752
+ case Kind::Subscript:
4753
+ case Kind::OptionalChain:
4754
+ case Kind::OptionalWrap:
4755
+ case Kind::OptionalForce:
4756
+ case Kind::Property:
4757
+ return true ;
4758
+
4759
+ case Kind::UnresolvedSubscript:
4760
+ case Kind::UnresolvedProperty:
4761
+ case Kind::Invalid:
4762
+ return false ;
4763
+ }
4764
+ }
4765
+
4747
4766
Expr *getIndexExpr () const {
4748
4767
switch (getKind ()) {
4749
4768
case Kind::Subscript:
Original file line number Diff line number Diff line change @@ -3986,6 +3986,20 @@ namespace {
3986
3986
if (E->getType ()->hasError ())
3987
3987
return E;
3988
3988
3989
+ // If a component is already resolved, then all of them should be
3990
+ // resolved, and we can let the expression be. This might happen when
3991
+ // re-checking a failed system for diagnostics.
3992
+ if (!E->getComponents ().empty ()
3993
+ && E->getComponents ().front ().isResolved ()) {
3994
+ assert ([&]{
3995
+ for (auto &c : E->getComponents ())
3996
+ if (!c.isResolved ())
3997
+ return false ;
3998
+ return true ;
3999
+ }());
4000
+ return E;
4001
+ }
4002
+
3989
4003
SmallVector<KeyPathExpr::Component, 4 > resolvedComponents;
3990
4004
3991
4005
// Resolve each of the components.
Original file line number Diff line number Diff line change @@ -2757,11 +2757,26 @@ namespace {
2757
2757
return ErrorType::get (CS.getASTContext ());
2758
2758
}
2759
2759
2760
- // If the key path contained any syntactically invalid components, bail
2761
- // out.
2762
- for ( auto &c : E-> getComponents ())
2763
- if (!c.isValid ())
2760
+ for ( auto &c : E-> getComponents ()) {
2761
+ // If the key path contained any syntactically invalid components, bail
2762
+ // out.
2763
+ if (!c.isValid ()) {
2764
2764
return ErrorType::get (CS.getASTContext ());
2765
+ }
2766
+
2767
+ // If a component is already resolved, then all of them should be
2768
+ // resolved, and we can let the expression be. This might happen when
2769
+ // re-checking a failed system for diagnostics.
2770
+ if (c.isResolved ()) {
2771
+ assert ([&]{
2772
+ for (auto &c : E->getComponents ())
2773
+ if (!c.isResolved ())
2774
+ return false ;
2775
+ return true ;
2776
+ }());
2777
+ return E->getType ();
2778
+ }
2779
+ }
2765
2780
2766
2781
// For native key paths, traverse the key path components to set up
2767
2782
// appropriate type relationships at each level.
Original file line number Diff line number Diff line change
1
+ // RUN: %target-swift-frontend -typecheck -verify %s
2
+
3
+ // Ensure that key path exprs can tolerate being re-type-checked when necessary
4
+ // to diagnose other errors in adjacent exprs.
5
+
6
+ struct P < T: K > { }
7
+
8
+ struct S {
9
+ init < B> ( _ a: P < B > ) {
10
+ fatalError ( )
11
+ }
12
+ }
13
+
14
+ protocol K { }
15
+
16
+ func + < Object> ( lhs: KeyPath < A , Object > , rhs: String ) -> P < Object > {
17
+ fatalError ( )
18
+ }
19
+
20
+ // expected-error@+1{{}}
21
+ func + ( lhs: KeyPath < A , String > , rhs: String ) -> P < String > {
22
+ fatalError ( )
23
+ }
24
+
25
+ struct A {
26
+ let id : String
27
+ }
28
+
29
+ extension A : K {
30
+ static let j = S ( \A . id + " id " )
31
+ }
You can’t perform that action at this time.
0 commit comments