@@ -1799,8 +1799,14 @@ namespace {
1799
1799
// /
1800
1800
// / \param locator The locator to use for generated constraints and
1801
1801
// / type variables.
1802
+ // /
1803
+ // / \param bindPatternVarsOneWay When true, generate fresh type variables
1804
+ // / for the types of each variable declared within the pattern, along
1805
+ // / with a one-way constraint binding that to the type to which the
1806
+ // / variable will be ascribed or inferred.
1802
1807
Type getTypeForPattern (
1803
1808
Pattern *pattern, ConstraintLocatorBuilder locator,
1809
+ bool bindPatternVarsOneWay,
1804
1810
PatternBindingDecl *patternBinding = nullptr ,
1805
1811
unsigned patternBindingIndex = 0 ) {
1806
1812
assert (pattern);
@@ -1819,13 +1825,15 @@ namespace {
1819
1825
auto *subPattern = paren->getSubPattern ();
1820
1826
auto underlyingType = getTypeForPattern (
1821
1827
subPattern,
1822
- locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)));
1828
+ locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)),
1829
+ bindPatternVarsOneWay);
1823
1830
1824
1831
return setType (underlyingType);
1825
1832
}
1826
1833
case PatternKind::Binding: {
1827
1834
auto *subPattern = cast<BindingPattern>(pattern)->getSubPattern ();
1828
- auto type = getTypeForPattern (subPattern, locator);
1835
+ auto type = getTypeForPattern (subPattern, locator,
1836
+ bindPatternVarsOneWay);
1829
1837
// Var doesn't affect the type.
1830
1838
return setType (type);
1831
1839
}
@@ -1921,64 +1929,99 @@ namespace {
1921
1929
var->getNameStr ().starts_with (" $__builder" );
1922
1930
};
1923
1931
1924
- // Otherwise, let's use the type of the pattern. The type
1925
- // of the declaration has to be r-value, so let's add an
1926
- // equality constraint if pattern type has any type variables
1927
- // that are allowed to be l-value.
1928
- bool foundLValueVars = false ;
1929
-
1930
- // Note that it wouldn't be always correct to allocate a single type
1931
- // variable, that disallows l-value types, to use as a declaration
1932
- // type because equality constraint would drop TVO_CanBindToLValue
1933
- // from the right-hand side (which is not the case for `OneWayEqual`)
1934
- // e.g.:
1935
- //
1936
- // struct S { var x, y: Int }
1937
- //
1938
- // func test(s: S) {
1939
- // let (x, y) = (s.x, s.y)
1940
- // }
1941
- //
1942
- // Single type variable approach results in the following constraint:
1943
- // `$T_x_y = ($T_s_x, $T_s_y)` where both `$T_s_x` and `$T_s_y` have
1944
- // to allow l-value, but `$T_x_y` does not. Early simplification of `=`
1945
- // constraint (due to right-hand side being a "concrete" tuple type)
1946
- // would drop l-value option from `$T_s_x` and `$T_s_y` which leads to
1947
- // a failure during member lookup because `x` and `y` are both
1948
- // `@lvalue Int`. To avoid that, declaration type would mimic pattern
1949
- // type with all l-value options stripped, so the equality constraint
1950
- // becomes `($T_x, $_T_y) = ($T_s_x, $T_s_y)` which doesn't result in
1951
- // stripping of l-value flag from the right-hand side since
1952
- // simplification can only happen when either side is resolved.
1953
- auto declTy = varType.transformRec ([&](Type type) -> std::optional<Type> {
1954
- if (auto *typeVar = type->getAs <TypeVariableType>()) {
1955
- if (typeVar->getImpl ().canBindToLValue ()) {
1956
- foundLValueVars = true ;
1957
-
1958
- // Drop l-value from the options but preserve the rest.
1959
- auto options = typeVar->getImpl ().getRawOptions ();
1960
- options &= ~TVO_CanBindToLValue;
1961
-
1962
- return Type (CS.createTypeVariable (typeVar->getImpl ().getLocator (),
1963
- options));
1964
- }
1965
- }
1966
- return std::nullopt;
1967
- });
1932
+ // When we are supposed to bind pattern variables, create a fresh
1933
+ // type variable and a one-way constraint to assign it to either the
1934
+ // deduced type or the externally-imposed type.
1935
+ Type oneWayVarType;
1936
+ if (bindPatternVarsOneWay) {
1937
+ oneWayVarType = CS.createTypeVariable (
1938
+ CS.getConstraintLocator (locator), TVO_CanBindToNoEscape);
1939
+
1940
+ // If there is externally-imposed type, and the variable
1941
+ // is marked as `weak`, let's fallthrough and allow the
1942
+ // `one-way` constraint to be fixed in diagnostic mode.
1943
+ //
1944
+ // That would make sure that type of this variable is
1945
+ // recorded in the constraint system, which would then
1946
+ // be used instead of `getVarType` upon discovering a
1947
+ // reference to this variable in subsequent expression(s).
1948
+ //
1949
+ // If we let constraint generation fail here, it would trigger
1950
+ // interface type request via `var->getType()` that would
1951
+ // attempt to validate `weak` attribute, and produce a
1952
+ // diagnostic in the middle of the solver path.
1968
1953
1969
- // If pattern types allows l-value types, let's create an
1970
- // equality constraint between r-value only declaration type
1971
- // and l-value pattern type that would take care of looking
1972
- // through l-values when necessary.
1973
- if (foundLValueVars) {
1974
- CS.addConstraint (ConstraintKind::Equal, declTy, varType,
1975
- CS.getConstraintLocator (locator));
1954
+ CS.addConstraint (ConstraintKind::OneWayEqual, oneWayVarType,
1955
+ varType, locator);
1956
+
1957
+ if (useLocatableTypes ())
1958
+ oneWayVarType = makeTypeLocatableIfPossible (oneWayVarType);
1976
1959
}
1977
1960
1978
- if (useLocatableTypes ())
1979
- declTy = makeTypeLocatableIfPossible (declTy);
1961
+ // Ascribe a type to the declaration so it's always available to
1962
+ // constraint system.
1963
+ if (oneWayVarType) {
1964
+ CS.setType (var, oneWayVarType);
1965
+ } else {
1966
+ // Otherwise, let's use the type of the pattern. The type
1967
+ // of the declaration has to be r-value, so let's add an
1968
+ // equality constraint if pattern type has any type variables
1969
+ // that are allowed to be l-value.
1970
+ bool foundLValueVars = false ;
1971
+
1972
+ // Note that it wouldn't be always correct to allocate a single type
1973
+ // variable, that disallows l-value types, to use as a declaration
1974
+ // type because equality constraint would drop TVO_CanBindToLValue
1975
+ // from the right-hand side (which is not the case for `OneWayEqual`)
1976
+ // e.g.:
1977
+ //
1978
+ // struct S { var x, y: Int }
1979
+ //
1980
+ // func test(s: S) {
1981
+ // let (x, y) = (s.x, s.y)
1982
+ // }
1983
+ //
1984
+ // Single type variable approach results in the following constraint:
1985
+ // `$T_x_y = ($T_s_x, $T_s_y)` where both `$T_s_x` and `$T_s_y` have
1986
+ // to allow l-value, but `$T_x_y` does not. Early simplification of `=`
1987
+ // constraint (due to right-hand side being a "concrete" tuple type)
1988
+ // would drop l-value option from `$T_s_x` and `$T_s_y` which leads to
1989
+ // a failure during member lookup because `x` and `y` are both
1990
+ // `@lvalue Int`. To avoid that, declaration type would mimic pattern
1991
+ // type with all l-value options stripped, so the equality constraint
1992
+ // becomes `($T_x, $_T_y) = ($T_s_x, $T_s_y)` which doesn't result in
1993
+ // stripping of l-value flag from the right-hand side since
1994
+ // simplification can only happen when either side is resolved.
1995
+ auto declTy = varType.transformRec ([&](Type type) -> std::optional<Type> {
1996
+ if (auto *typeVar = type->getAs <TypeVariableType>()) {
1997
+ if (typeVar->getImpl ().canBindToLValue ()) {
1998
+ foundLValueVars = true ;
1999
+
2000
+ // Drop l-value from the options but preserve the rest.
2001
+ auto options = typeVar->getImpl ().getRawOptions ();
2002
+ options &= ~TVO_CanBindToLValue;
2003
+
2004
+ return Type (CS.createTypeVariable (typeVar->getImpl ().getLocator (),
2005
+ options));
2006
+ }
2007
+ }
2008
+ return std::nullopt;
2009
+ });
2010
+
2011
+ // If pattern types allows l-value types, let's create an
2012
+ // equality constraint between r-value only declaration type
2013
+ // and l-value pattern type that would take care of looking
2014
+ // through l-values when necessary.
2015
+ if (foundLValueVars) {
2016
+ CS.addConstraint (ConstraintKind::Equal, declTy, varType,
2017
+ CS.getConstraintLocator (locator));
2018
+ }
2019
+
2020
+ if (useLocatableTypes ())
2021
+ declTy = makeTypeLocatableIfPossible (declTy);
1980
2022
1981
- CS.setType (var, declTy);
2023
+ CS.setType (var, declTy);
2024
+ }
1982
2025
1983
2026
return setType (varType);
1984
2027
}
@@ -2007,7 +2050,8 @@ namespace {
2007
2050
// ascribed type.
2008
2051
Type subPatternType = getTypeForPattern (
2009
2052
subPattern,
2010
- locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)));
2053
+ locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)),
2054
+ bindPatternVarsOneWay);
2011
2055
2012
2056
// NOTE: The order here is important! Pattern matching equality is
2013
2057
// not symmetric (we need to fix that either by using a different
@@ -2035,7 +2079,8 @@ namespace {
2035
2079
auto *eltPattern = tupleElt.getPattern ();
2036
2080
Type eltTy = getTypeForPattern (
2037
2081
eltPattern,
2038
- locator.withPathElement (LocatorPathElt::PatternMatch (eltPattern)));
2082
+ locator.withPathElement (LocatorPathElt::PatternMatch (eltPattern)),
2083
+ bindPatternVarsOneWay);
2039
2084
2040
2085
tupleTypeElts.push_back (TupleTypeElt (eltTy, tupleElt.getLabel ()));
2041
2086
}
@@ -2048,7 +2093,8 @@ namespace {
2048
2093
// The subpattern must have optional type.
2049
2094
Type subPatternType = getTypeForPattern (
2050
2095
subPattern,
2051
- locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)));
2096
+ locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)),
2097
+ bindPatternVarsOneWay);
2052
2098
2053
2099
return setType (OptionalType::get (subPatternType));
2054
2100
}
@@ -2078,7 +2124,8 @@ namespace {
2078
2124
if (auto *subPattern = isPattern->getSubPattern ()) {
2079
2125
auto subPatternType = getTypeForPattern (
2080
2126
subPattern,
2081
- locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)));
2127
+ locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)),
2128
+ bindPatternVarsOneWay);
2082
2129
2083
2130
// NOTE: The order here is important! Pattern matching equality is
2084
2131
// not symmetric (we need to fix that either by using a different
@@ -2181,7 +2228,8 @@ namespace {
2181
2228
// types.
2182
2229
Type subPatternType = getTypeForPattern (
2183
2230
subPattern,
2184
- locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)));
2231
+ locator.withPathElement (LocatorPathElt::PatternMatch (subPattern)),
2232
+ bindPatternVarsOneWay);
2185
2233
2186
2234
SmallVector<AnyFunctionType::Param, 4 > params;
2187
2235
decomposeTuple (subPatternType, params);
@@ -3608,7 +3656,7 @@ static bool generateInitPatternConstraints(ConstraintSystem &cs,
3608
3656
Type patternType;
3609
3657
if (auto pattern = target.getInitializationPattern ()) {
3610
3658
patternType = cs.generateConstraints (
3611
- pattern, locator,
3659
+ pattern, locator, target. shouldBindPatternVarsOneWay (),
3612
3660
target.getInitializationPatternBindingDecl (),
3613
3661
target.getInitializationPatternBindingIndex ());
3614
3662
} else {
@@ -3659,7 +3707,8 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc,
3659
3707
// / expression that conforms to `Swift.Sequence`.
3660
3708
static std::optional<SequenceIterationInfo>
3661
3709
generateForEachStmtConstraints (ConstraintSystem &cs, DeclContext *dc,
3662
- ForEachStmt *stmt, Pattern *typeCheckedPattern) {
3710
+ ForEachStmt *stmt, Pattern *typeCheckedPattern,
3711
+ bool shouldBindPatternVarsOneWay) {
3663
3712
ASTContext &ctx = cs.getASTContext ();
3664
3713
bool isAsync = stmt->getAwaitLoc ().isValid ();
3665
3714
auto *sequenceExpr = stmt->getParsedSequence ();
@@ -3735,7 +3784,8 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc,
3735
3784
ctx, StaticSpellingKind::None, pattern, makeIteratorCall, dc);
3736
3785
3737
3786
auto makeIteratorTarget = SyntacticElementTarget::forInitialization (
3738
- makeIteratorCall, /* patternType=*/ Type (), PB, /* index=*/ 0 );
3787
+ makeIteratorCall, /* patternType=*/ Type (), PB, /* index=*/ 0 ,
3788
+ /* shouldBindPatternsOneWay=*/ false );
3739
3789
3740
3790
ContextualTypeInfo contextInfo (sequenceProto->getDeclaredInterfaceType (),
3741
3791
CTP_ForEachSequence);
@@ -3830,7 +3880,8 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc,
3830
3880
3831
3881
// Generate constraints for the pattern.
3832
3882
Type initType =
3833
- cs.generateConstraints (typeCheckedPattern, elementLocator, nullptr , 0 );
3883
+ cs.generateConstraints (typeCheckedPattern, elementLocator,
3884
+ shouldBindPatternVarsOneWay, nullptr , 0 );
3834
3885
if (!initType)
3835
3886
return std::nullopt;
3836
3887
@@ -3882,7 +3933,8 @@ generateForEachPreambleConstraints(ConstraintSystem &cs,
3882
3933
3883
3934
// Generate constraints for the pattern.
3884
3935
Type patternType = cs.generateConstraints (
3885
- pattern, elementLocator, nullptr , 0 );
3936
+ pattern, elementLocator, target.shouldBindPatternVarsOneWay (), nullptr ,
3937
+ 0 );
3886
3938
if (!patternType)
3887
3939
return std::nullopt;
3888
3940
@@ -3899,8 +3951,8 @@ generateForEachPreambleConstraints(ConstraintSystem &cs,
3899
3951
3900
3952
target.getForEachStmtInfo () = *packIterationInfo;
3901
3953
} else {
3902
- auto sequenceIterationInfo =
3903
- generateForEachStmtConstraints ( cs, dc, stmt, pattern);
3954
+ auto sequenceIterationInfo = generateForEachStmtConstraints (
3955
+ cs, dc, stmt, pattern, target. shouldBindPatternVarsOneWay () );
3904
3956
if (!sequenceIterationInfo) {
3905
3957
return std::nullopt;
3906
3958
}
@@ -4057,7 +4109,8 @@ bool ConstraintSystem::generateConstraints(
4057
4109
}
4058
4110
4059
4111
auto target = init ? SyntacticElementTarget::forInitialization (
4060
- init, patternType, patternBinding, index)
4112
+ init, patternType, patternBinding, index,
4113
+ /* bindPatternVarsOneWay=*/ true )
4061
4114
: SyntacticElementTarget::forUninitializedVar (
4062
4115
patternBinding, index, patternType);
4063
4116
@@ -4089,7 +4142,7 @@ bool ConstraintSystem::generateConstraints(
4089
4142
// Generate constraints to bind all of the internal declarations
4090
4143
// and verify the pattern.
4091
4144
Type patternType = generateConstraints (
4092
- pattern, locator,
4145
+ pattern, locator, /* shouldBindPatternVarsOneWay */ true ,
4093
4146
target.getPatternBindingOfUninitializedVar (),
4094
4147
target.getIndexOfUninitializedVar ());
4095
4148
@@ -4124,10 +4177,11 @@ Expr *ConstraintSystem::generateConstraints(Expr *expr, DeclContext *dc) {
4124
4177
4125
4178
Type ConstraintSystem::generateConstraints (
4126
4179
Pattern *pattern, ConstraintLocatorBuilder locator,
4127
- PatternBindingDecl *patternBinding,
4180
+ bool bindPatternVarsOneWay, PatternBindingDecl *patternBinding,
4128
4181
unsigned patternIndex) {
4129
4182
ConstraintGenerator cg (*this , nullptr );
4130
- auto ty = cg.getTypeForPattern (pattern, locator, patternBinding, patternIndex);
4183
+ auto ty = cg.getTypeForPattern (pattern, locator, bindPatternVarsOneWay,
4184
+ patternBinding, patternIndex);
4131
4185
assert (ty);
4132
4186
4133
4187
// Gather the ExprPatterns, and form a conjunction for their expressions.
@@ -4188,7 +4242,8 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition,
4188
4242
return true ;
4189
4243
4190
4244
auto target = SyntacticElementTarget::forInitialization (
4191
- condElement.getInitializer (), dc, Type (), pattern);
4245
+ condElement.getInitializer (), dc, Type (), pattern,
4246
+ /* bindPatternVarsOneWay=*/ true );
4192
4247
if (generateConstraints (target, FreeTypeVariableBinding::Disallow))
4193
4248
return true ;
4194
4249
0 commit comments