Skip to content

Begin refactoring type variable binding code. #15128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
280 changes: 149 additions & 131 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,135 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding(
Bindings.push_back(std::move(binding));
}

Optional<ConstraintSystem::PotentialBinding>
ConstraintSystem::getPotentialBindingForRelationalConstraint(
PotentialBindings &result, Constraint *constraint,
bool &hasDependentMemberRelationalConstraints,
bool &hasNonDependentMemberRelationalConstraints,
bool &addOptionalSupertypeBindings) {
assert(constraint->getClassification() ==
ConstraintClassification::Relational &&
"only relational constraints handled here");

auto *typeVar = result.TypeVar;

// Record constraint which contributes to the
// finding of potential bindings.
result.Sources.insert(constraint);

auto first = simplifyType(constraint->getFirstType());
auto second = simplifyType(constraint->getSecondType());

if (first->is<TypeVariableType>() && first->isEqual(second))
return None;

Type type;
AllowedBindingKind kind;
if (first->getAs<TypeVariableType>() == typeVar) {
// Upper bound for this type variable.
type = second;
kind = AllowedBindingKind::Subtypes;
} else if (second->getAs<TypeVariableType>() == typeVar) {
// Lower bound for this type variable.
type = first;
kind = AllowedBindingKind::Supertypes;
} else {
// Can't infer anything.
if (result.InvolvesTypeVariables)
return None;

// Check whether both this type and another type variable are
// inferable.
SmallPtrSet<TypeVariableType *, 4> typeVars;
findInferableTypeVars(first, typeVars);
findInferableTypeVars(second, typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
return None;
}

// Do not attempt to bind to ErrorType.
if (type->hasError())
return None;

// If the source of the binding is 'OptionalObject' constraint
// and type variable is on the left-hand side, that means
// that it _has_ to be of optional type, since the right-hand
// side of the constraint is object type of the optional.
if (constraint->getKind() == ConstraintKind::OptionalObject &&
kind == AllowedBindingKind::Subtypes) {
type = OptionalType::get(type);
}

// If the type we'd be binding to is a dependent member, don't try to
// resolve this type variable yet.
if (type->is<DependentMemberType>()) {
if (!ConstraintSystem::typeVarOccursInType(typeVar, type,
&result.InvolvesTypeVariables)) {
hasDependentMemberRelationalConstraints = true;
}
return None;
}
hasNonDependentMemberRelationalConstraints = true;

// Check whether we can perform this binding.
// FIXME: this has a super-inefficient extraneous simplifyType() in it.
bool isNilLiteral = false;
bool *isNilLiteralPtr = nullptr;
if (!addOptionalSupertypeBindings && kind == AllowedBindingKind::Supertypes)
isNilLiteralPtr = &isNilLiteral;
if (auto boundType = checkTypeOfBinding(typeVar, type, isNilLiteralPtr)) {
type = *boundType;
if (type->hasTypeVariable())
result.InvolvesTypeVariables = true;
} else {
// If the bound is a 'nil' literal type, add optional supertype bindings.
if (isNilLiteral) {
addOptionalSupertypeBindings = true;
return None;
}

result.InvolvesTypeVariables = true;
return None;
}

// Don't deduce autoclosure types or single-element, non-variadic
// tuples.
if (shouldBindToValueType(constraint)) {
if (auto funcTy = type->getAs<FunctionType>()) {
if (funcTy->isAutoClosure())
type = funcTy->getResult();
}

type = type->getWithoutImmediateLabel();
}

// Make sure we aren't trying to equate type variables with different
// lvalue-binding rules.
if (auto otherTypeVar =
type->lookThroughAllOptionalTypes()->getAs<TypeVariableType>()) {
if (typeVar->getImpl().canBindToLValue() !=
otherTypeVar->getImpl().canBindToLValue())
return None;
}

// BindParam constraints are not reflexive and must be treated specially.
if (constraint->getKind() == ConstraintKind::BindParam) {
if (kind == AllowedBindingKind::Subtypes) {
if (auto *lvt = type->getAs<LValueType>()) {
type = InOutType::get(lvt->getObjectType());
}
} else if (kind == AllowedBindingKind::Supertypes) {
if (auto *iot = type->getAs<InOutType>()) {
type = LValueType::get(iot->getObjectType());
}
}
kind = AllowedBindingKind::Exact;
}

return PotentialBinding{type, kind, constraint->getKind()};
}

/// \brief Retrieve the set of potential type bindings for the given
/// representative type variable, along with flags indicating whether
/// those types should be opened.
Expand Down Expand Up @@ -238,9 +367,19 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
case ConstraintKind::ArgumentTupleConversion:
case ConstraintKind::OperatorArgumentTupleConversion:
case ConstraintKind::OperatorArgumentConversion:
case ConstraintKind::OptionalObject:
// Relational constraints: break out to look for types above/below.
case ConstraintKind::OptionalObject: {
auto binding = getPotentialBindingForRelationalConstraint(
result, constraint, hasDependentMemberRelationalConstraints,
hasNonDependentMemberRelationalConstraints,
addOptionalSupertypeBindings);
if (!binding)
break;

auto type = binding->BindingType;
if (exactTypes.insert(type->getCanonicalType()).second)
result.addPotentialBinding(*binding);
break;
}

case ConstraintKind::BridgingConversion:
case ConstraintKind::CheckedCast:
Expand All @@ -249,7 +388,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
case ConstraintKind::KeyPath:
case ConstraintKind::KeyPathApplication:
// Constraints from which we can't do anything.
continue;
break;

case ConstraintKind::DynamicTypeOf: {
// Direct binding of the left-hand side could result
Expand All @@ -264,7 +403,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
}

// This is right-hand side, let's continue.
continue;
break;
}

case ConstraintKind::Defaultable:
Expand All @@ -274,13 +413,13 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
defaultableConstraints.push_back(constraint);
hasNonDependentMemberRelationalConstraints = true;
}
continue;
break;

case ConstraintKind::Disjunction:
// FIXME: Recurse into these constraints to see whether this
// type variable is fully bound by any of them.
result.InvolvesTypeVariables = true;
continue;
break;

case ConstraintKind::ConformsTo:
case ConstraintKind::SelfObjectOfProtocol:
Expand Down Expand Up @@ -350,7 +489,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
constraint->getProtocol()});
}

continue;
break;
}

case ConstraintKind::ApplicableFunction:
Expand All @@ -373,7 +512,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
continue;

break;
}

case ConstraintKind::ValueMember:
Expand All @@ -395,130 +535,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
&result.InvolvesTypeVariables)) {
result.FullyBound = true;
}
continue;
}

// Handle relational constraints.
assert(constraint->getClassification() ==
ConstraintClassification::Relational &&
"only relational constraints handled here");

// Record constraint which contributes to the
// finding of pontential bindings.
result.Sources.insert(constraint);

auto first = simplifyType(constraint->getFirstType());
auto second = simplifyType(constraint->getSecondType());

if (first->is<TypeVariableType>() && first->isEqual(second))
continue;

Type type;
AllowedBindingKind kind;
if (first->getAs<TypeVariableType>() == typeVar) {
// Upper bound for this type variable.
type = second;
kind = AllowedBindingKind::Subtypes;
} else if (second->getAs<TypeVariableType>() == typeVar) {
// Lower bound for this type variable.
type = first;
kind = AllowedBindingKind::Supertypes;
} else {
// Can't infer anything.
if (result.InvolvesTypeVariables)
continue;

// Check whether both this type and another type variable are
// inferable.
SmallPtrSet<TypeVariableType *, 4> typeVars;
findInferableTypeVars(first, typeVars);
findInferableTypeVars(second, typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
continue;
}

// Do not attempt to bind to ErrorType.
if (type->hasError())
continue;

// If the source of the binding is 'OptionalObject' constraint
// and type variable is on the left-hand side, that means
// that it _has_ to be of optional type, since the right-hand
// side of the constraint is object type of the optional.
if (constraint->getKind() == ConstraintKind::OptionalObject &&
kind == AllowedBindingKind::Subtypes) {
type = OptionalType::get(type);
}

// If the type we'd be binding to is a dependent member, don't try to
// resolve this type variable yet.
if (type->is<DependentMemberType>()) {
if (!ConstraintSystem::typeVarOccursInType(
typeVar, type, &result.InvolvesTypeVariables)) {
hasDependentMemberRelationalConstraints = true;
}
continue;
}
hasNonDependentMemberRelationalConstraints = true;

// Check whether we can perform this binding.
// FIXME: this has a super-inefficient extraneous simplifyType() in it.
bool isNilLiteral = false;
bool *isNilLiteralPtr = nullptr;
if (!addOptionalSupertypeBindings && kind == AllowedBindingKind::Supertypes)
isNilLiteralPtr = &isNilLiteral;
if (auto boundType = checkTypeOfBinding(typeVar, type, isNilLiteralPtr)) {
type = *boundType;
if (type->hasTypeVariable())
result.InvolvesTypeVariables = true;
} else {
// If the bound is a 'nil' literal type, add optional supertype bindings.
if (isNilLiteral) {
addOptionalSupertypeBindings = true;
continue;
}

result.InvolvesTypeVariables = true;
continue;
}

// Don't deduce autoclosure types or single-element, non-variadic
// tuples.
if (shouldBindToValueType(constraint)) {
if (auto funcTy = type->getAs<FunctionType>()) {
if (funcTy->isAutoClosure())
type = funcTy->getResult();
}

type = type->getWithoutImmediateLabel();
}

// Make sure we aren't trying to equate type variables with different
// lvalue-binding rules.
if (auto otherTypeVar =
type->lookThroughAllOptionalTypes()->getAs<TypeVariableType>()) {
if (typeVar->getImpl().canBindToLValue() !=
otherTypeVar->getImpl().canBindToLValue())
continue;
}

// BindParam constraints are not reflexive and must be treated specially.
if (constraint->getKind() == ConstraintKind::BindParam) {
if (kind == AllowedBindingKind::Subtypes) {
if (auto *lvt = type->getAs<LValueType>()) {
type = InOutType::get(lvt->getObjectType());
}
} else if (kind == AllowedBindingKind::Supertypes) {
if (auto *iot = type->getAs<InOutType>()) {
type = LValueType::get(iot->getObjectType());
}
}
kind = AllowedBindingKind::Exact;
break;
}

if (exactTypes.insert(type->getCanonicalType()).second)
result.addPotentialBinding({type, kind, constraint->getKind()});
}

// If we have any literal constraints, check whether there is already a
Expand Down
10 changes: 10 additions & 0 deletions lib/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2866,6 +2866,16 @@ class ConstraintSystem {
Optional<Type> checkTypeOfBinding(TypeVariableType *typeVar, Type type,
bool *isNilLiteral = nullptr);
Optional<PotentialBindings> determineBestBindings();
Optional<ConstraintSystem::PotentialBinding>
getPotentialBindingForRelationalConstraint(
PotentialBindings &result, Constraint *constraint,
bool &hasDependentMemberRelationalConstraints,
bool &hasNonDependentMemberRelationalConstraints,
bool &addOptionalSupertypeBindings);

Optional<PotentialBinding>
getPotentialBindingForRelationalConstraint(PotentialBindings &result,
Constraint *constraint);
PotentialBindings getPotentialBindings(TypeVariableType *typeVar);

bool
Expand Down