Merge pull request #22072 from jckarter/opaque-type-runtime

Opaque types with resilience
This commit is contained in:
Joe Groff
2019-04-18 14:52:31 -07:00
committed by GitHub
143 changed files with 4501 additions and 579 deletions

View File

@@ -1082,6 +1082,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
subKind = ConstraintKind::Conversion;
break;
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::Bind:
case ConstraintKind::BindParam:
case ConstraintKind::BindToPointerType:
@@ -1144,6 +1145,7 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
case ConstraintKind::Equal:
return rep1 != rep2;
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::Subtype:
case ConstraintKind::Conversion:
case ConstraintKind::BridgingConversion:
@@ -1313,6 +1315,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentConversion:
case ConstraintKind::OperatorArgumentConversion:
case ConstraintKind::OpaqueUnderlyingType:
subKind = ConstraintKind::Subtype;
break;
@@ -1566,11 +1569,49 @@ ConstraintSystem::matchSuperclassTypes(Type type1, Type type2,
return getTypeMatchFailure(locator);
}
static ConstraintSystem::TypeMatchResult
matchDeepTypeArguments(ConstraintSystem &cs,
ConstraintSystem::TypeMatchOptions subflags,
ArrayRef<Type> args1,
ArrayRef<Type> args2,
ConstraintLocatorBuilder locator) {
if (args1.size() != args2.size()) {
return cs.getTypeMatchFailure(locator);
}
for (unsigned i = 0, n = args1.size(); i != n; ++i) {
auto result = cs.matchTypes(args1[i], args2[i], ConstraintKind::Bind,
subflags, locator.withPathElement(
LocatorPathElt::getGenericArgument(i)));
if (result.isFailure())
return result;
}
return cs.getTypeMatchSuccess();
}
ConstraintSystem::TypeMatchResult
ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
ConstraintLocatorBuilder locator) {
TypeMatchOptions subflags = TMF_GenerateConstraints;
// Handle opaque archetypes.
if (auto arch1 = type1->getAs<ArchetypeType>()) {
auto arch2 = type2->castTo<ArchetypeType>();
auto opaque1 = cast<OpaqueTypeArchetypeType>(arch1->getRoot());
auto opaque2 = cast<OpaqueTypeArchetypeType>(arch2->getRoot());
assert(arch1->getInterfaceType()->getCanonicalType(
opaque1->getGenericEnvironment()->getGenericSignature())
== arch2->getInterfaceType()->getCanonicalType(
opaque2->getGenericEnvironment()->getGenericSignature()));
assert(opaque1->getDecl() == opaque2->getDecl());
auto args1 = opaque1->getSubstitutions().getReplacementTypes();
auto args2 = opaque2->getSubstitutions().getReplacementTypes();
// Match up the replacement types of the respective substitution maps.
return matchDeepTypeArguments(*this, subflags, args1, args2, locator);
}
// Handle nominal types that are not directly generic.
if (auto nominal1 = type1->getAs<NominalType>()) {
auto nominal2 = type2->castTo<NominalType>();
@@ -1605,19 +1646,7 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
// Match up the generic arguments, exactly.
auto args1 = bound1->getGenericArgs();
auto args2 = bound2->getGenericArgs();
if (args1.size() != args2.size()) {
return getTypeMatchFailure(locator);
}
for (unsigned i = 0, n = args1.size(); i != n; ++i) {
auto result = matchTypes(args1[i], args2[i], ConstraintKind::Bind,
subflags, locator.withPathElement(
LocatorPathElt::getGenericArgument(i)));
if (result.isFailure())
return result;
}
return getTypeMatchSuccess();
return matchDeepTypeArguments(*this, subflags, args1, args2, locator);
}
ConstraintSystem::TypeMatchResult
@@ -2184,6 +2213,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
case ConstraintKind::OperatorArgumentConversion:
return formUnsolvedResult();
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::ApplicableFunction:
case ConstraintKind::DynamicCallableApplicableFunction:
case ConstraintKind::BindOverload:
@@ -2253,7 +2283,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
case TypeKind::Module:
case TypeKind::PrimaryArchetype:
case TypeKind::OpenedArchetype:
case TypeKind::NestedArchetype:
// If two module types or archetypes were not already equal, there's
// nothing more we can do.
return getTypeMatchFailure(locator);
@@ -2383,6 +2412,48 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
break;
}
// Opaque archetypes are globally bound, so we can match them for deep
// equality.
case TypeKind::OpaqueTypeArchetype: {
auto opaque1 = cast<OpaqueTypeArchetypeType>(desugar1);
auto opaque2 = cast<OpaqueTypeArchetypeType>(desugar2);
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
if (!type1->is<LValueType>()
&& opaque1->getDecl() == opaque2->getDecl()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
}
break;
}
// Same for nested archetypes rooted in opaque types.
case TypeKind::NestedArchetype: {
auto nested1 = cast<NestedArchetypeType>(desugar1);
auto nested2 = cast<NestedArchetypeType>(desugar2);
auto rootOpaque1 = dyn_cast<OpaqueTypeArchetypeType>(nested1->getRoot());
auto rootOpaque2 = dyn_cast<OpaqueTypeArchetypeType>(nested2->getRoot());
if (rootOpaque1 && rootOpaque2) {
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
auto interfaceTy1 = nested1->getInterfaceType()
->getCanonicalType(rootOpaque1->getGenericEnvironment()
->getGenericSignature());
auto interfaceTy2 = nested2->getInterfaceType()
->getCanonicalType(rootOpaque2->getGenericEnvironment()
->getGenericSignature());
if (!type1->is<LValueType>()
&& interfaceTy1 == interfaceTy2
&& rootOpaque1->getDecl() == rootOpaque2->getDecl()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
break;
}
}
// If the archetypes aren't rooted in an opaque type, or are rooted in
// completely different decls, then there's nothing else we can do.
return getTypeMatchFailure(locator);
}
}
}
@@ -2942,6 +3013,7 @@ ConstraintSystem::simplifyConstructionConstraint(
case TypeKind::PrimaryArchetype:
case TypeKind::OpenedArchetype:
case TypeKind::NestedArchetype:
case TypeKind::OpaqueTypeArchetype:
case TypeKind::DynamicSelf:
case TypeKind::ProtocolComposition:
case TypeKind::Protocol:
@@ -4604,6 +4676,40 @@ ConstraintSystem::simplifyDynamicTypeOfConstraint(
return SolutionKind::Error;
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyOpaqueUnderlyingTypeConstraint(Type type1, Type type2,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
// Open the second type, which must be an opaque archetype, to try to
// infer the first type using its constraints.
auto opaque2 = type2->castTo<OpaqueTypeArchetypeType>();
// Open the generic signature of the opaque decl, and bind the "outer" generic
// params to our context. The remaining axes of freedom on the type variable
// corresponding to the underlying type should be the constraints on the
// underlying return type.
OpenedTypeMap replacements;
openGeneric(nullptr, DC, opaque2->getBoundSignature(),
/*skip self*/ false,
locator, replacements);
auto underlyingTyVar = openType(opaque2->getInterfaceType(),
replacements);
assert(underlyingTyVar);
if (auto dcSig = DC->getGenericSignatureOfContext()) {
for (auto param : dcSig->getGenericParams()) {
addConstraint(ConstraintKind::Bind,
openType(param, replacements),
DC->mapTypeIntoContext(param),
locator);
}
}
addConstraint(ConstraintKind::Equal, type1, underlyingTyVar, locator);
return getTypeMatchSuccess();
}
ConstraintSystem::SolutionKind
ConstraintSystem::simplifyBridgingConstraint(Type type1,
Type type2,
@@ -6368,6 +6474,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
case ConstraintKind::OperatorArgumentConversion:
return matchTypes(first, second, kind, subflags, locator);
case ConstraintKind::OpaqueUnderlyingType:
return simplifyOpaqueUnderlyingTypeConstraint(first, second,
subflags, locator);
case ConstraintKind::BridgingConversion:
return simplifyBridgingConstraint(first, second, subflags, locator);
@@ -6620,7 +6730,8 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
case ConstraintKind::Subtype:
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentConversion:
case ConstraintKind::OperatorArgumentConversion: {
case ConstraintKind::OperatorArgumentConversion:
case ConstraintKind::OpaqueUnderlyingType: {
// Relational constraints.
auto matchKind = constraint.getKind();