mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
AST: Use TypeTransform::transformSubMap() to transform TypeAliasType
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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; };
|
||||
|
||||
|
||||
@@ -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'}}
|
||||
|
||||
|
||||
|
||||
|
||||
41
test/Constraints/phantom_existential_typealias.swift
Normal file
41
test/Constraints/phantom_existential_typealias.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -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)?#];
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {}
|
||||
|
||||
Reference in New Issue
Block a user