AST: Use TypeTransform::transformSubMap() to transform TypeAliasType

This commit is contained in:
Slava Pestov
2024-08-13 16:08:55 -04:00
parent ae77d6f0c1
commit 074684fe06
6 changed files with 61 additions and 29 deletions

View File

@@ -433,23 +433,28 @@ case TypeKind::Id:
if (!newParentType) return newUnderlyingTy;
}
auto subMap = alias->getSubstitutionMap();
for (Type oldReplacementType : subMap.getReplacementTypes()) {
Type newReplacementType = doIt(oldReplacementType, TypePosition::Invariant);
if (!newReplacementType)
return newUnderlyingTy;
if (newParentType && newParentType->isExistentialType())
return newUnderlyingTy;
// If anything changed with the replacement type, we lose the sugar.
// FIXME: This is really unfortunate.
if (newReplacementType.getPointer() != oldReplacementType.getPointer())
return newUnderlyingTy;
}
auto oldSubMap = alias->getSubstitutionMap();
auto newSubMap = asDerived().transformSubMap(oldSubMap);
if (oldSubMap && !newSubMap)
return Type();
if (oldParentType.getPointer() == newParentType.getPointer() &&
oldUnderlyingTy.getPointer() == newUnderlyingTy.getPointer())
oldUnderlyingTy.getPointer() == newUnderlyingTy.getPointer() &&
oldSubMap == newSubMap)
return t;
return TypeAliasType::get(alias->getDecl(), newParentType, subMap,
// Don't leave local archetypes and type variables behind in sugar
// if they don't appear in the underlying type, to avoid confusion.
auto props = newSubMap.getRecursiveProperties();
if (props.hasLocalArchetype() && !newUnderlyingTy->hasLocalArchetype())
return newUnderlyingTy;
if (props.hasTypeVariable() && !newUnderlyingTy->hasTypeVariable())
return newUnderlyingTy;
return TypeAliasType::get(alias->getDecl(), newParentType, newSubMap,
newUnderlyingTy);
}

View File

@@ -536,20 +536,6 @@ TypeSubstituter::transform(TypeBase *type, TypePosition position) {
return std::nullopt;
}
// Special-case TypeAliasType; we need to substitute conformances.
if (auto aliasTy = dyn_cast<TypeAliasType>(type)) {
Type parentTy;
if (auto origParentTy = aliasTy->getParent())
parentTy = doIt(origParentTy, TypePosition::Invariant);
auto underlyingTy = doIt(aliasTy->getSinglyDesugaredType(),
TypePosition::Invariant);
if (parentTy && parentTy->isExistentialType())
return underlyingTy;
auto subMap = aliasTy->getSubstitutionMap().subst(IFS);
return Type(TypeAliasType::get(aliasTy->getDecl(), parentTy,
subMap, underlyingTy));
}
auto oldLevel = level;
SWIFT_DEFER { level = oldLevel; };

View File

@@ -389,7 +389,7 @@ func rdar21078316() {
// <rdar://problem/20978044> QoI: Poor diagnostic when using an incorrect tuple element in a closure
var numbers = [1, 2, 3]
zip(numbers, numbers).filter { $0.2 > 1 } // expected-error {{value of tuple type '(Int, Int)' has no member '2'}}
zip(numbers, numbers).filter { $0.2 > 1 } // expected-error {{value of tuple type 'Zip2Sequence<[Int], [Int]>.Element' (aka '(Int, Int)') has no member '2'}}

View File

@@ -0,0 +1,41 @@
// RUN: %target-typecheck-verify-swift
// This is an elaborate reduction for a problem where we create a TypeAliasType
// with a concrete underlying type, but type variables in its substitutions.
//
// Specifically, we get something like `G<$1, $2>.B` below, but the underlying
// type of B is just S, it does not depend on its generic arguments.
//
// The solver doesn't simplify the type variables away in this case, so to
// avoid problems the TypeTransform desugars the typealias in this case.
public protocol P {
associatedtype A
}
public struct Horse<A>: P {}
public struct S {}
@resultBuilder
public enum E<A, B> {
public static func buildExpression<T: P>(_ t: T) -> T where T.A == A {
return t
}
public static func buildBlock<T: P>(_ t: T) -> T {
return t
}
}
public struct G<A, C: P> where C.A == A {
public typealias B = S
public init(_: A.Type, @E<A, B> _: () -> C) {}
}
func testHorse() {
_ = G(S.self) {
Horse()
}
}

View File

@@ -1119,7 +1119,7 @@ func testLValueBaseTyOfSubscript() {
var cache: [String: Codable] = [:]
if let cached = cache[#^LVALUEBASETY^#
// LVALUEBASETY-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(position): Dictionary<String, any Codable>.Index#}[']'][#(key: String, value: any Codable)#];
// LVALUEBASETY-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(position): Dictionary<String, any Codable>.Index#}[']'][#Dictionary<String, any Codable>.Element#];
// LVALUEBASETY-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(key): String#}[']'][#@lvalue (any Codable)?#];
}

View File

@@ -55,5 +55,5 @@ func testIdentifier(notOkay: Stringified<String> = #stringify(myString)) {}
// expected-error@+1{{only literals are permitted}}
func testString(interpolated: Stringified<String> = #stringify("Hello \(0b10001)")) {}
// expected-error@+1{{default argument value of type '(Int, String)' cannot be converted to type 'Int'}}
// expected-error@+1{{default argument value of type 'Stringified<Int>' (aka '(Int, String)') cannot be converted to type 'Int'}}
func testReturn(wrongType: Int = #stringify(0)) {}