Skip to content

Commit d06d126

Browse files
authored
Merge pull request #84666 from hamishknight/can-opener
[CS] Consolidate placeholder handling logic into `Solution::simplifyType`
2 parents 8edfd9c + 9e4208b commit d06d126

22 files changed

+159
-231
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,11 @@ class Solution {
16771677
/// \param wantInterfaceType If true, maps the resulting type out of context,
16781678
/// and replaces type variables for opened generic parameters with the
16791679
/// generic parameter types. Should only be used for diagnostic logic.
1680-
Type simplifyType(Type type, bool wantInterfaceType = false) const;
1680+
/// \param forCompletion If true, will produce archetypes instead of
1681+
/// ErrorTypes for generic parameter originators, which is what completion
1682+
/// currently expects for the code completion token.
1683+
Type simplifyType(Type type, bool wantInterfaceType = false,
1684+
bool forCompletion = false) const;
16811685

16821686
// To aid code completion, we need to attempt to convert type placeholders
16831687
// back into underlying generic parameters if possible, since type

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -96,42 +96,12 @@ Type FailureDiagnostic::getRawType(ASTNode node) const {
9696

9797
Type FailureDiagnostic::resolveType(Type rawType, bool reconstituteSugar,
9898
bool wantRValue) const {
99-
rawType = rawType.transformRec([&](Type type) -> std::optional<Type> {
100-
if (auto *typeVar = type->getAs<TypeVariableType>()) {
101-
auto resolvedType = S.simplifyType(typeVar);
102-
103-
if (!resolvedType->hasError())
104-
return resolvedType;
105-
106-
// If type variable was simplified to an unresolved pack expansion
107-
// type, let's examine its original pattern type because it could
108-
// contain type variables replaceable with their generic parameter
109-
// types.
110-
if (auto *expansion = resolvedType->getAs<PackExpansionType>()) {
111-
auto *locator = typeVar->getImpl().getLocator();
112-
auto *openedExpansionTy =
113-
locator->castLastElementTo<LocatorPathElt::PackExpansionType>()
114-
.getOpenedType();
115-
auto patternType = resolveType(openedExpansionTy->getPatternType());
116-
return PackExpansionType::get(patternType, expansion->getCountType());
117-
}
118-
119-
Type GP = typeVar->getImpl().getGenericParameter();
120-
return resolvedType->is<ErrorType>() && GP
121-
? ErrorType::get(GP)
122-
: resolvedType;
123-
}
124-
125-
if (type->hasElementArchetype()) {
126-
auto *env = getDC()->getGenericEnvironmentOfContext();
127-
return env->mapElementTypeIntoPackContext(type);
128-
}
129-
130-
if (type->isPlaceholder())
131-
return ErrorType::get(type->getASTContext());
99+
rawType = S.simplifyType(rawType);
132100

133-
return std::nullopt;
134-
});
101+
if (rawType->hasElementArchetype()) {
102+
auto *env = getDC()->getGenericEnvironmentOfContext();
103+
rawType = env->mapElementTypeIntoPackContext(rawType);
104+
}
135105

136106
if (reconstituteSugar)
137107
rawType = rawType->reconstituteSugar(/*recursive*/ true);

lib/Sema/ConstraintSystem.cpp

Lines changed: 83 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,7 +1861,82 @@ void Solution::recordSingleArgMatchingChoice(ConstraintLocator *locator) {
18611861
MatchCallArgumentResult::forArity(1)});
18621862
}
18631863

1864-
Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
1864+
static GenericTypeParamType *
1865+
getGenericParamForHoleTypeVar(TypeVariableType *tv, const Solution &S) {
1866+
auto getGenericParam = [](TypeVariableType *tv) -> GenericTypeParamType * {
1867+
auto *gp = tv->getImpl().getGenericParameter();
1868+
if (!gp)
1869+
return nullptr;
1870+
// Note we only consider generic parameters with underlying decls since for
1871+
// diagnostics we want something we can print, and for completion we want
1872+
// something we can extract a GenericEnvironment to produce an archetype.
1873+
return gp->getDecl() ? gp : nullptr;
1874+
};
1875+
1876+
if (auto *gp = getGenericParam(tv))
1877+
return gp;
1878+
1879+
// Sometimes we run into cases where the originator of a hole isn't for
1880+
// the generic parameter, instead it's for a member of its equivalence
1881+
// class. Handle this by looking through all the bindings to see if we have
1882+
// the same hole bound to a generic parameter type variable.
1883+
for (auto &binding : S.typeBindings) {
1884+
if (auto *hole = binding.second->getAs<PlaceholderType>()) {
1885+
if (hole->getOriginator().dyn_cast<TypeVariableType *>() == tv) {
1886+
if (auto *gp = getGenericParam(binding.first))
1887+
return gp;
1888+
}
1889+
}
1890+
}
1891+
return nullptr;
1892+
}
1893+
1894+
static Type replacePlaceholderType(PlaceholderType *placeholder,
1895+
const Solution &S, bool forCompletion) {
1896+
auto &ctx = S.getConstraintSystem().getASTContext();
1897+
auto origTy = [&]() -> Type {
1898+
auto orig = placeholder->getOriginator();
1899+
if (auto *tv = orig.dyn_cast<TypeVariableType *>())
1900+
return tv;
1901+
if (auto *dmt = orig.dyn_cast<DependentMemberType *>())
1902+
return dmt;
1903+
return Type();
1904+
}();
1905+
if (!origTy)
1906+
return ErrorType::get(ctx);
1907+
1908+
// Try replace the type variable with its original generic parameter type.
1909+
auto replacement = origTy.transformRec([&](Type ty) -> std::optional<Type> {
1910+
auto *tv = dyn_cast<TypeVariableType>(ty.getPointer());
1911+
if (!tv)
1912+
return std::nullopt;
1913+
1914+
auto *gp = getGenericParamForHoleTypeVar(tv, S);
1915+
if (!gp)
1916+
return std::nullopt;
1917+
1918+
return Type(gp);
1919+
});
1920+
if (isa<TypeVariableType>(replacement.getPointer()))
1921+
return ErrorType::get(ctx);
1922+
1923+
// For completion, we want to produce an archetype instead of an ErrorType
1924+
// for a top-level generic parameter.
1925+
// FIXME: This is pretty weird, we're producing a contextual type outside of
1926+
// the context it exists in. We ought to see if we can make the completion
1927+
// logic work with ErrorTypes instead.
1928+
if (forCompletion) {
1929+
if (auto *GP = replacement->getAs<GenericTypeParamType>())
1930+
return GP->getDecl()->getInnermostDeclContext()->mapTypeIntoContext(GP);
1931+
}
1932+
// Return an ErrorType with the replacement as the original type. Note that
1933+
// if we failed to replace a type variable with a generic parameter in a
1934+
// dependent member, `ErrorType::get` will fold it away.
1935+
return ErrorType::get(replacement);
1936+
}
1937+
1938+
Type Solution::simplifyType(Type type, bool wantInterfaceType,
1939+
bool forCompletion) const {
18651940
// If we've been asked for an interface type, start by mapping any archetypes
18661941
// out of context.
18671942
if (wantInterfaceType)
@@ -1899,7 +1974,11 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
18991974
return type;
19001975

19011976
auto *typePtr = type.getPointer();
1902-
if (isa<TypeVariableType>(typePtr) || isa<PlaceholderType>(typePtr))
1977+
1978+
if (auto *placeholder = dyn_cast<PlaceholderType>(typePtr))
1979+
return replacePlaceholderType(placeholder, *this, forCompletion);
1980+
1981+
if (isa<TypeVariableType>(typePtr))
19031982
return ErrorType::get(ctx);
19041983

19051984
return std::nullopt;
@@ -1911,136 +1990,8 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
19111990
}
19121991

19131992
Type Solution::simplifyTypeForCodeCompletion(Type Ty) const {
1914-
auto &CS = getConstraintSystem();
1915-
1916-
// First, instantiate all type variables that we know, but don't replace
1917-
// placeholders by unresolved types.
1918-
Ty = CS.simplifyTypeImpl(Ty, [this](TypeVariableType *typeVar) -> Type {
1919-
return getFixedType(typeVar);
1920-
});
1921-
1922-
// Next, replace all placeholders by type variables. We know that all type
1923-
// variables now in the type originate from placeholders.
1924-
Ty = Ty.transformRec([](Type type) -> std::optional<Type> {
1925-
if (auto *placeholder = type->getAs<PlaceholderType>()) {
1926-
if (auto *typeVar =
1927-
placeholder->getOriginator().dyn_cast<TypeVariableType *>()) {
1928-
return Type(typeVar);
1929-
}
1930-
}
1931-
1932-
return std::nullopt;
1933-
});
1934-
1935-
// Replace all type variables (which must come from placeholders) by their
1936-
// generic parameters. Because we call into simplifyTypeImpl
1937-
Ty = CS.simplifyTypeImpl(Ty, [&CS, this](TypeVariableType *typeVar) -> Type {
1938-
// Code completion depends on generic parameter type being represented in
1939-
// terms of `ArchetypeType` since it's easy to extract protocol requirements
1940-
// from it.
1941-
auto getTypeVarAsArchetype = [](TypeVariableType *typeVar) -> Type {
1942-
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
1943-
if (auto *GPD = GP->getDecl()) {
1944-
return GPD->getInnermostDeclContext()->mapTypeIntoContext(GP);
1945-
}
1946-
}
1947-
return Type();
1948-
};
1949-
1950-
if (auto archetype = getTypeVarAsArchetype(typeVar)) {
1951-
return archetype;
1952-
}
1953-
1954-
// Sometimes the type variable itself doesn't have have an originator that
1955-
// can be replaced by an archetype but one of its equivalent type variable
1956-
// does.
1957-
// Search thorough all equivalent type variables, looking for one that can
1958-
// be replaced by a generic parameter.
1959-
std::vector<std::pair<TypeVariableType *, Type>> bindings(
1960-
typeBindings.begin(), typeBindings.end());
1961-
// Make sure we iterate the bindings in a deterministic order.
1962-
llvm::sort(bindings, [](const std::pair<TypeVariableType *, Type> &lhs,
1963-
const std::pair<TypeVariableType *, Type> &rhs) {
1964-
return lhs.first->getID() < rhs.first->getID();
1965-
});
1966-
for (auto binding : bindings) {
1967-
if (auto placeholder = binding.second->getAs<PlaceholderType>()) {
1968-
if (placeholder->getOriginator().dyn_cast<TypeVariableType *>() ==
1969-
typeVar) {
1970-
if (auto archetype = getTypeVarAsArchetype(binding.first)) {
1971-
return archetype;
1972-
}
1973-
}
1974-
}
1975-
}
1976-
1977-
// When applying the logic below to get contextual types inside result
1978-
// builders, the code completion type variable is connected by a one-way
1979-
// constraint to a type variable in the buildBlock call, but that is not the
1980-
// type variable that represents the argument type. We need to find the type
1981-
// variable representing the argument to retrieve protocol requirements from
1982-
// it. Look for a ArgumentConversion constraint that allows us to retrieve
1983-
// the argument type var.
1984-
auto &cg = CS.getConstraintGraph();
1985-
1986-
// FIXME: The type variable is not going to be part of the constraint graph
1987-
// at this point unless it was created at the outermost decision level;
1988-
// otherwise it has already been rolled back! Work around this by creating
1989-
// an empty node if one doesn't exist.
1990-
cg.addTypeVariable(typeVar);
1991-
1992-
for (auto argConstraint : cg[typeVar].getConstraints()) {
1993-
if (argConstraint->getKind() == ConstraintKind::ArgumentConversion &&
1994-
argConstraint->getFirstType()->getRValueType()->isEqual(typeVar)) {
1995-
if (auto argTV =
1996-
argConstraint->getSecondType()->getAs<TypeVariableType>()) {
1997-
if (auto archetype = getTypeVarAsArchetype(argTV)) {
1998-
return archetype;
1999-
}
2000-
}
2001-
}
2002-
}
2003-
2004-
return typeVar;
2005-
});
2006-
2007-
// Logic to determine the contextual type inside buildBlock result builders:
2008-
//
2009-
// When completing inside a result builder, the result builder
2010-
// @ViewBuilder var body: some View {
2011-
// Text("Foo")
2012-
// #^COMPLETE^#
2013-
// }
2014-
// gets rewritten to
2015-
// @ViewBuilder var body: some View {
2016-
// let $__builder2: Text
2017-
// let $__builder0 = Text("Foo")
2018-
// let $__builder1 = #^COMPLETE^#
2019-
// $__builder2 = ViewBuilder.buildBlock($__builder0, $__builder1)
2020-
// return $__builder2
2021-
// }
2022-
// Inside the constraint system
2023-
// let $__builder1 = #^COMPLETE^#
2024-
// gets type checked without context, so we can't know the contextual type for
2025-
// the code completion token. But we know that $__builder1 (and thus the type
2026-
// of #^COMPLETE^#) is used as the second argument to ViewBuilder.buildBlock,
2027-
// so we can extract the contextual type from that call. To do this, figure
2028-
// out the type variable that is used for $__builder1 in the buildBlock call.
2029-
// This type variable is connected to the type variable of $__builder1's
2030-
// definition by a one-way constraint.
2031-
if (auto TV = Ty->getAs<TypeVariableType>()) {
2032-
for (auto constraint : CS.getConstraintGraph()[TV].getConstraints()) {
2033-
if (constraint->getKind() == ConstraintKind::OneWayEqual &&
2034-
constraint->getSecondType()->isEqual(TV)) {
2035-
return simplifyTypeForCodeCompletion(constraint->getFirstType());
2036-
}
2037-
}
2038-
}
2039-
2040-
// Remove any remaining type variables and placeholders
2041-
Ty = simplifyType(Ty);
2042-
2043-
return Ty->getRValueType();
1993+
return simplifyType(Ty, /*wantInterfaceType*/ false, /*forCompletion*/ true)
1994+
->getRValueType();
20441995
}
20451996

20461997
template <typename T>

test/Constraints/diag_missing_arg.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ func attributedInOutFunc(x: inout @convention(c) () -> Int32) {} // expected-not
1919
attributedInOutFunc() // expected-error {{missing argument for parameter 'x' in call}} {{21-21=x: &<#@convention(c) () -> Int32#>}}
2020

2121
func genericFunc1<T>(x: T) {} // expected-note * {{here}}
22-
genericFunc1() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#_#>}}
22+
genericFunc1() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#T#>}}
2323

2424
protocol P {}
2525
func genericFunc2<T : P>(x: T) {} // expected-note * {{here}}
26-
genericFunc2() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#_#>}}
26+
genericFunc2() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#T#>}}
2727

2828
typealias MyInt = Int
2929
func aliasedFunc(x: MyInt) {} // expected-note * {{here}}

test/Constraints/generics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,8 +1040,8 @@ func test_requirement_failures_in_ambiguous_context() {
10401040
// rdar://106054263 - failed to produce a diagnostic upon generic argument mismatch
10411041
func test_mismatches_with_dependent_member_generic_arguments() {
10421042
struct Binding<T, U> {}
1043-
// expected-note@-1 {{arguments to generic parameter 'T' ('Double?' and 'Data.SomeAssociated') are expected to be equal}}
1044-
// expected-note@-2 {{arguments to generic parameter 'U' ('Int' and 'Data.SomeAssociated') are expected to be equal}}
1043+
// expected-note@-1 {{arguments to generic parameter 'T' ('Double?' and 'Data.SomeAssociated' (aka 'String')) are expected to be equal}}
1044+
// expected-note@-2 {{arguments to generic parameter 'U' ('Int' and 'Data.SomeAssociated' (aka 'String')) are expected to be equal}}
10451045

10461046
struct Data : SomeProtocol {
10471047
typealias SomeAssociated = String
@@ -1058,7 +1058,7 @@ func test_mismatches_with_dependent_member_generic_arguments() {
10581058

10591059
test2(Optional<Int>(nil), Data())
10601060
// expected-error@-1 {{cannot convert value of type 'Optional<Int>' to expected argument type 'Optional<Data.SomeAssociated>'}}
1061-
// expected-note@-2 {{arguments to generic parameter 'Wrapped' ('Int' and 'Data.SomeAssociated') are expected to be equal}}
1061+
// expected-note@-2 {{arguments to generic parameter 'Wrapped' ('Int' and 'Data.SomeAssociated' (aka 'String')) are expected to be equal}}
10621062
}
10631063

10641064
extension Dictionary where Value == Any { // expected-note {{where 'Value' = 'any P'}}

test/Constraints/pack_expansion_types.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,10 @@ func patternInstantiationConcreteValid() {
240240

241241
func patternInstantiationConcreteInvalid() {
242242
let _: Set<Int> = patternInstantiationTupleTest1()
243-
// expected-error@-1 {{cannot convert value of type '(repeat Array<_>)' to specified type 'Set<Int>'}}
243+
// expected-error@-1 {{cannot convert value of type 'Array<_>' to specified type 'Set<Int>'}}
244244
// expected-error@-2 {{could not infer pack element #0 from context}}
245245

246-
let _: (Array<Int>, Set<String>) = patternInstantiationTupleTest1() // expected-error {{'(repeat Array<Int, _>)' is not convertible to '(Array<Int>, Set<String>)', tuples have a different number of elements}}
246+
let _: (Array<Int>, Set<String>) = patternInstantiationTupleTest1() // expected-error {{cannot convert value of type '(Array<Int>, Array<_>)' to specified type '(Array<Int>, Set<String>)'}}
247247
// expected-error@-1 {{could not infer pack element #1 from context}}
248248
}
249249

@@ -274,7 +274,7 @@ func patternInstantiationGenericInvalid<each T: Hashable>(t: repeat each T) {
274274
let _: (repeat Set<each T>) = patternInstantiationTupleTest1() // expected-error {{cannot convert value of type '(repeat Array<each T>)' to specified type '(repeat Set<each T>)}}
275275
// expected-error@-1 {{generic parameter 'each T' could not be inferred}}
276276

277-
let _: (repeat Array<each T>, Set<String>) = patternInstantiationTupleTest1() // expected-error {{'(repeat Array<repeat each T, _>)' is not convertible to '(repeat Array<each T>, Set<String>)', tuples have a different number of elements}}
277+
let _: (repeat Array<each T>, Set<String>) = patternInstantiationTupleTest1() // expected-error {{cannot convert value of type '(repeat Array<each T>, Array<_>)' to specified type '(repeat Array<each T>, Set<String>)'}}
278278
// expected-error@-1 {{could not infer pack element #1 from context}}
279279
}
280280

test/Constraints/tuple_arguments.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,7 @@ do {
17281728
do {
17291729
func f(_: Int...) {}
17301730
let _ = [(1, 2, 3)].map(f) // expected-error {{no exact matches in call to instance method 'map'}}
1731-
// expected-note@-1 {{found candidate with type '(((Int, Int, Int)) -> _) -> Array<_>'}}
1731+
// expected-note@-1 2{{found candidate with type '(((Int, Int, Int)) -> T) -> [T]'}}
17321732
}
17331733

17341734
// rdar://problem/48443263 - cannot convert value of type '() -> Void' to expected argument type '(_) -> Void'

test/Generics/issue-55666.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ struct W<T> {}
77
struct S<C1: Collection> {
88
init(){}
99
// expected-note@+2 {{where 'C1.Element' = 'W<C1>', 'main.W<C2.Element>' = 'main.W<C2.Element>'}}
10-
// expected-note@+1 {{where 'C1.Element' = 'W<String>', 'W<C2.Element>' = 'W<Array<Int>.Element>'}}
10+
// expected-note@+1 {{where 'C1.Element' = 'W<String>', 'W<C2.Element>' = 'W<Int>'}}
1111
init<C2>(_ c2: W<C2>) where C2: Collection, C1.Element == W<C2.Element> {}
12-
// expected-note@+1 {{where 'C1.Element' = 'W<String>', 'W<C2.Element>' = 'W<Array<Int>.Element>'}}
12+
// expected-note@+1 {{where 'C1.Element' = 'W<String>', 'W<C2.Element>' = 'W<Int>'}}
1313
static func f<C2>(_ c2: W<C2>) where C2: Collection, C1.Element == W<C2.Element> {}
14-
// expected-note@+1 {{where 'C1.Element' = 'W<String>', 'W<C2.Element>' = 'W<Array<Int>.Element>'}}
14+
// expected-note@+1 {{where 'C1.Element' = 'W<String>', 'W<C2.Element>' = 'W<Int>'}}
1515
func instancef<C2>(_ c2: W<C2>) where C2: Collection, C1.Element == W<C2.Element> {}
1616
}
17-
let _ = S<[W<String>]>(W<[Int]>()) // expected-error{{initializer 'init(_:)' requires the types 'W<String>' and 'W<Array<Int>.Element>' be equivalent}}
18-
let _ = S<[W<String>]>.f(W<[Int]>()) // expected-error{{static method 'f' requires the types 'W<String>' and 'W<Array<Int>.Element>' be equivalent}}
19-
let _ = S<[W<String>]>().instancef(W<[Int]>()) // expected-error{{instance method 'instancef' requires the types 'W<String>' and 'W<Array<Int>.Element>' be equivalent}}
17+
let _ = S<[W<String>]>(W<[Int]>()) // expected-error{{initializer 'init(_:)' requires the types 'W<String>' and 'W<Int>' be equivalent}}
18+
let _ = S<[W<String>]>.f(W<[Int]>()) // expected-error{{static method 'f' requires the types 'W<String>' and 'W<Int>' be equivalent}}
19+
let _ = S<[W<String>]>().instancef(W<[Int]>()) // expected-error{{instance method 'instancef' requires the types 'W<String>' and 'W<Int>' be equivalent}}
2020

2121
// Archetypes requirement failure
2222
func genericFunc<C1: Collection, C2: Collection>(_ c2: W<C2>, c1: C1.Type) where C1.Element == W<C2.Element> {

0 commit comments

Comments
 (0)