Merge pull request #5626 from DougGregor/dependent-type-variables

[Type checker] Use DependentMemberType instead of type variables for nested types.
This commit is contained in:
Doug Gregor
2016-11-06 07:27:19 -08:00
committed by GitHub
21 changed files with 367 additions and 425 deletions
+1 -14
View File
@@ -121,11 +121,6 @@ enum class KnownFoundationEntity {
/// entity name.
Optional<KnownFoundationEntity> getKnownFoundationEntity(StringRef name);
/// Callback function used when referring to a type member of a given
/// type variable.
typedef std::function<Type(TypeVariableType *, AssociatedTypeDecl *)>
GetTypeVariableMemberCallback;
/// \brief Introduces a new constraint checker arena, whose lifetime is
/// tied to the lifetime of this RAII object.
class ConstraintCheckerArenaRAII {
@@ -142,8 +137,7 @@ public:
/// \param allocator The allocator used for allocating any data that
/// goes into the constraint checker arena.
ConstraintCheckerArenaRAII(ASTContext &self,
llvm::BumpPtrAllocator &allocator,
GetTypeVariableMemberCallback getTypeMember);
llvm::BumpPtrAllocator &allocator);
ConstraintCheckerArenaRAII(const ConstraintCheckerArenaRAII &) = delete;
ConstraintCheckerArenaRAII(ConstraintCheckerArenaRAII &&) = delete;
@@ -519,13 +513,6 @@ public:
const CanType TheIEEE128Type; /// 128-bit IEEE floating point
const CanType ThePPC128Type; /// 128-bit PowerPC 2xDouble
/// Retrieve a type member of the given base type variable.
///
/// Note that this routine is only usable when a constraint system
/// is active.
Type getTypeVariableMemberType(TypeVariableType *baseTypeVar,
AssociatedTypeDecl *assocType);
/// Adds a search path to SearchPathOpts, unless it is already present.
///
/// Does any proper bookkeeping to keep all module loaders up to date as well.
+13 -17
View File
@@ -330,12 +330,8 @@ struct ASTContext::Implementation {
/// The allocator used for all allocations within this arena.
llvm::BumpPtrAllocator &Allocator;
/// Callback used to get a type member of a type variable.
GetTypeVariableMemberCallback GetTypeMember;
ConstraintSolverArena(llvm::BumpPtrAllocator &allocator,
GetTypeVariableMemberCallback &&getTypeMember)
: Allocator(allocator), GetTypeMember(std::move(getTypeMember)) { }
ConstraintSolverArena(llvm::BumpPtrAllocator &allocator)
: Allocator(allocator) { }
ConstraintSolverArena(const ConstraintSolverArena &) = delete;
ConstraintSolverArena(ConstraintSolverArena &&) = delete;
@@ -369,14 +365,11 @@ ASTContext::Implementation::~Implementation() {
}
ConstraintCheckerArenaRAII::
ConstraintCheckerArenaRAII(ASTContext &self, llvm::BumpPtrAllocator &allocator,
GetTypeVariableMemberCallback getTypeMember)
ConstraintCheckerArenaRAII(ASTContext &self, llvm::BumpPtrAllocator &allocator)
: Self(self), Data(self.Impl.CurrentConstraintSolverArena.release())
{
Self.Impl.CurrentConstraintSolverArena.reset(
new ASTContext::Implementation::ConstraintSolverArena(
allocator,
std::move(getTypeMember)));
new ASTContext::Implementation::ConstraintSolverArena(allocator));
}
ConstraintCheckerArenaRAII::~ConstraintCheckerArenaRAII() {
@@ -1164,12 +1157,6 @@ void ASTContext::setSubstitutions(TypeBase* type,
boundGenericSubstitutions[{type, gpContext}] = Subs;
}
Type ASTContext::getTypeVariableMemberType(TypeVariableType *baseTypeVar,
AssociatedTypeDecl *assocType) {
auto &arena = *Impl.CurrentConstraintSolverArena;
return arena.GetTypeMember(baseTypeVar, assocType);
}
void ASTContext::addSearchPath(StringRef searchPath, bool isFramework) {
OptionSet<SearchPathKind> &loaded = Impl.SearchPathsSet[searchPath];
auto kind = isFramework ? SearchPathKind::Framework : SearchPathKind::Import;
@@ -1386,6 +1373,15 @@ ASTContext::getBehaviorConformance(Type conformingType,
auto conformance = new (*this, AllocationArena::Permanent)
NormalProtocolConformance(conformingType, conformingInterfaceType,
protocol, loc, storage, state);
if (auto nominal = conformingInterfaceType->getAnyNominal()) {
// Note: this is an egregious hack. The conformances need to be associated
// with the actual storage declarations.
SmallVector<ProtocolConformance *, 2> conformances;
if (!nominal->lookupConformance(nominal->getModuleContext(), protocol,
conformances))
nominal->registerProtocolConformance(conformance);
}
return conformance;
}
+9 -10
View File
@@ -586,28 +586,24 @@ TypeBase::gatherAllSubstitutions(Module *module,
// The type itself contains substitutions up to the innermost
// non-type context.
CanType parent(canon);
auto *parentDC = gpContext;
ArrayRef<GenericTypeParamType *> genericParams =
genericSig->getGenericParams();
unsigned lastGenericIndex = genericParams.size();
while (parent) {
if (auto boundGeneric = dyn_cast<BoundGenericType>(parent)) {
auto genericSig = parentDC->getGenericSignatureOfContext();
unsigned index = 0;
assert(boundGeneric->getGenericArgs().size() ==
genericSig->getInnermostGenericParams().size());
unsigned index = lastGenericIndex - boundGeneric->getGenericArgs().size();
for (Type arg : boundGeneric->getGenericArgs()) {
auto paramTy = genericSig->getInnermostGenericParams()[index++];
auto paramTy = genericParams[index++];
substitutions[paramTy->getCanonicalType().getPointer()] = arg;
}
lastGenericIndex -= boundGeneric->getGenericArgs().size();
parent = CanType(boundGeneric->getParent());
parentDC = parentDC->getParent();
continue;
}
if (auto nominal = dyn_cast<NominalType>(parent)) {
parent = CanType(nominal->getParent());
parentDC = parentDC->getParent();
continue;
}
@@ -616,6 +612,9 @@ TypeBase::gatherAllSubstitutions(Module *module,
// Add forwarding substitutions from the outer context if we have
// a type nested inside a generic function.
auto *parentDC = gpContext;
while (parentDC->isTypeContext())
parentDC = parentDC->getParent();
if (auto *outerEnv = parentDC->getGenericEnvironmentOfContext())
for (auto pair : outerEnv->getInterfaceToArchetypeMap()) {
auto result = substitutions.insert(pair);
+11 -8
View File
@@ -521,7 +521,13 @@ public:
Type visitParenType(ParenType *pt) {
return ParenType::get(pt->getASTContext(), visit(pt->getUnderlyingType()));
}
Type visitSubstitutedType(SubstitutedType *st) {
return SubstitutedType::get(st->getOriginal(),
visit(st->getReplacementType()),
st->getASTContext());
}
Type visitType(TypeBase *t) {
// Other types should not structurally contain lvalues.
assert(!t->isLValueType()
@@ -2774,13 +2780,10 @@ static Type getMemberForBaseType(ConformanceSource conformances,
return getDependentMemberType(ErrorType::get(substBase));
}
// If the parent is a type variable, retrieve its member type
// variable.
if (auto typeVarParent = substBase->getAs<TypeVariableType>()) {
assert(assocType && "Missing associated type");
return substBase->getASTContext().getTypeVariableMemberType(typeVarParent,
assocType);
}
// If the parent is a type variable or a member rooted in a type variable,
// we're done.
if (substBase->isTypeVariableOrMember())
return getDependentMemberType(substBase);
// Retrieve the member type with the given name.
+6 -20
View File
@@ -1690,17 +1690,11 @@ namespace {
locator);
// Its subexpression should be convertible to a tuple (T.Element...).
// FIXME: We should really go through the conformance above to extract
// the element type, rather than just looking for the element type.
// FIXME: Member constraint is still weird here.
ConstraintLocatorBuilder builder(locator);
auto arrayElementTy = CS.getMemberType(arrayTy, elementAssocTy,
builder.withPathElement(
ConstraintLocator::Member),
/*options=*/0);
Type arrayElementTy = DependentMemberType::get(arrayTy, elementAssocTy);
// Introduce conversions from each element to the element type of the
// array.
ConstraintLocatorBuilder builder(locator);
unsigned index = 0;
for (auto element : expr->getElements()) {
CS.addConstraint(ConstraintKind::Conversion,
@@ -1758,18 +1752,10 @@ namespace {
// Its subexpression should be convertible to a tuple ((T.Key,T.Value)...).
ConstraintLocatorBuilder locatorBuilder(locator);
auto dictionaryKeyTy = CS.getMemberType(dictionaryTy,
keyAssocTy,
locatorBuilder.withPathElement(
ConstraintLocator::Member),
/*options=*/0);
/// FIXME: ArrayElementType is a total hack here.
auto dictionaryValueTy = CS.getMemberType(dictionaryTy,
valueAssocTy,
locatorBuilder.withPathElement(
ConstraintLocator::ArrayElementType),
/*options=*/0);
auto dictionaryKeyTy = DependentMemberType::get(dictionaryTy,
keyAssocTy);
auto dictionaryValueTy = DependentMemberType::get(dictionaryTy,
valueAssocTy);
TupleTypeElt tupleElts[2] = { TupleTypeElt(dictionaryKeyTy),
TupleTypeElt(dictionaryValueTy) };
Type elementTy = TupleType::get(tupleElts, C);
+15 -6
View File
@@ -1438,8 +1438,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}
bool isTypeVarOrMember1 = desugar1->isTypeVariableOrMember();
bool isTypeVarOrMember2 = desugar2->isTypeVariableOrMember();
llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes;
bool concrete = !typeVar1 && !typeVar2;
bool concrete = !isTypeVarOrMember1 && !isTypeVarOrMember2;
// If this is an argument conversion, handle it directly. The rules are
// different from normal conversions.
@@ -1482,9 +1485,12 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
return SolutionKind::Error;
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
llvm_unreachable("unmapped dependent type in type checker");
case TypeKind::DependentMember:
// Nothing we can solve.
return formUnsolvedResult();
case TypeKind::TypeVariable:
case TypeKind::Archetype:
// Nothing to do here; handle type variables and archetypes below.
@@ -2077,7 +2083,7 @@ commit_to_conversions:
// If we should attempt fixes, add those to the list. They'll only be visited
// if there are no other possible solutions.
if (shouldAttemptFixes() && !typeVar1 && !typeVar2 &&
if (shouldAttemptFixes() && !isTypeVarOrMember1 && !isTypeVarOrMember2 &&
!flags.contains(TMF_ApplyingFix) && kind >= ConstraintKind::Conversion) {
Type objectType1 = type1->getRValueObjectType();
@@ -2136,8 +2142,10 @@ commit_to_conversions:
}
if (conversionsOrFixes.empty()) {
// If one of the types is a type variable, we leave this unsolved.
if (typeVar1 || typeVar2) return formUnsolvedResult();
// If one of the types is a type variable or member thereof, we leave this
// unsolved.
if (isTypeVarOrMember1 || isTypeVarOrMember2)
return formUnsolvedResult();
return SolutionKind::Error;
}
@@ -2200,6 +2208,7 @@ ConstraintSystem::SolutionKind
ConstraintSystem::simplifyConstructionConstraint(
Type valueType, FunctionType *fnType, TypeMatchOptions flags,
FunctionRefKind functionRefKind, ConstraintLocator *locator) {
// Desugar the value type.
auto desugarValueType = valueType->getDesugaredType();
@@ -2223,10 +2232,10 @@ ConstraintSystem::simplifyConstructionConstraint(
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
llvm_unreachable("unmapped dependent type");
case TypeKind::TypeVariable:
case TypeKind::DependentMember:
return SolutionKind::Unsolved;
case TypeKind::Tuple: {
+140 -14
View File
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "ConstraintSystem.h"
#include "ConstraintGraph.h"
#include "swift/AST/TypeWalker.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -30,6 +31,7 @@ using namespace constraints;
#define JOIN(X,Y) JOIN2(X,Y)
#define JOIN2(X,Y) X##Y
STATISTIC(NumSolutionAttempts, "# of solution attempts");
STATISTIC(TotalNumTypeVariables, "# of type variables created");
#define CS_STATISTIC(Name, Description) \
STATISTIC(JOIN2(Overall,Name), Description);
@@ -42,6 +44,16 @@ STATISTIC(NumSolutionAttempts, "# of solution attempts");
#include "ConstraintSolverStats.def"
STATISTIC(LargestSolutionAttemptNumber, "# of the largest solution attempt");
TypeVariableType *ConstraintSystem::createTypeVariable(
ConstraintLocator *locator,
unsigned options) {
++TotalNumTypeVariables;
auto tv = TypeVariableType::getNew(TC.Context, assignTypeVariableID(),
locator, options);
addTypeVariable(tv);
return tv;
}
/// \brief Check whether the given type can be used as a binding for the given
/// type variable.
///
@@ -633,6 +645,48 @@ namespace {
break;
}
}
void dump(TypeVariableType *typeVar, llvm::raw_ostream &out,
unsigned indent) const {
out.indent(indent);
out << "(";
if (typeVar)
out << "$T" << typeVar->getImpl().getID();
if (FullyBound)
out << " fully_bound";
if (SubtypeOfExistentialType)
out << " subtype_of_existential";
if (LiteralBinding != LiteralBindingKind::None)
out << " literal=" << static_cast<int>(LiteralBinding);
if (InvolvesTypeVariables)
out << " involves_type_vars";
if (NumDefaultableBindings > 0)
out << " defaultable_bindings=" << NumDefaultableBindings;
out << " bindings=";
interleave(Bindings, [&](const PotentialBinding &binding) {
auto type = binding.BindingType;
auto &ctx = type->getASTContext();
llvm::SaveAndRestore<bool>
debugConstraints(ctx.LangOpts.DebugConstraintSolver, true);
switch (binding.Kind) {
case AllowedBindingKind::Exact:
break;
case AllowedBindingKind::Subtypes:
out << "(subtypes of) ";
break;
case AllowedBindingKind::Supertypes:
out << "(supertypes of) ";
break;
}
if (binding.DefaultedProtocol)
out << "(default from " << (*binding.DefaultedProtocol)->getName()
<< ") ";
out << type.getString();
}, [&]() { out << " "; });
out << ")\n";
}
};
}
@@ -674,6 +728,37 @@ static bool shouldBindToValueType(Constraint *constraint)
}
}
/// Find the set of type variables that are inferrable from the given type.
///
/// \param type The type to search.
/// \param typeVars Collects the type variables that are inferrable from the
/// given type. This set is not cleared, so that multiple types can be explored
/// and introduce their results into the same set.
static void findInferrableTypeVars(
Type type,
SmallPtrSetImpl<TypeVariableType *> &typeVars) {
type = type->getCanonicalType();
if (!type->hasTypeVariable()) return;
class Walker : public TypeWalker {
SmallPtrSetImpl<TypeVariableType *> &typeVars;
public:
explicit Walker(SmallPtrSetImpl<TypeVariableType *> &typeVars)
: typeVars(typeVars) { }
virtual Action walkToTypePre(Type ty) override {
if (ty->is<DependentMemberType>())
return Action::SkipChildren;
if (auto typeVar = ty->getAs<TypeVariableType>())
typeVars.insert(typeVar);
return Action::Continue;
}
};
type.walk(Walker(typeVars));
}
/// \brief Retrieve the set of potential type bindings for the given
/// representative type variable, along with flags indicating whether
/// those types should be opened.
@@ -727,6 +812,8 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
SmallVector<Constraint *, 2> defaultableConstraints;
bool addOptionalSupertypeBindings = false;
auto &tc = cs.getTypeChecker();
bool hasNonDependentMemberRelationalConstraints = false;
bool hasDependentMemberRelationalConstraints = false;
for (auto constraint : constraints) {
// Only visit each constraint once.
if (!visitedConstraints.insert(constraint).second)
@@ -761,8 +848,10 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
case ConstraintKind::Defaultable:
// Do these in a separate pass.
if (cs.getFixedTypeRecursive(constraint->getFirstType(), true)
->getAs<TypeVariableType>() == typeVar)
->getAs<TypeVariableType>() == typeVar) {
defaultableConstraints.push_back(constraint);
hasNonDependentMemberRelationalConstraints = true;
}
continue;
case ConstraintKind::Disjunction:
@@ -795,6 +884,7 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
// Note that we have a literal constraint with this protocol.
literalProtocols.insert(constraint->getProtocol());
hasNonDependentMemberRelationalConstraints = true;
// Handle unspecialized types directly.
if (!defaultType->isUnspecializedGeneric()) {
@@ -838,15 +928,23 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
case ConstraintKind::ApplicableFunction:
case ConstraintKind::BindOverload: {
if (result.FullyBound && result.InvolvesTypeVariables) continue;
// If this variable is in the left-hand side, it is fully bound.
// FIXME: Can we avoid simplification here by walking the graph? Is it
// worthwhile?
if (ConstraintSystem::typeVarOccursInType(
typeVar,
cs.simplifyType(constraint->getFirstType()),
&result.InvolvesTypeVariables)) {
SmallPtrSet<TypeVariableType *, 4> typeVars;
findInferrableTypeVars(cs.simplifyType(constraint->getFirstType()),
typeVars);
if (typeVars.count(typeVar))
result.FullyBound = true;
}
if (result.InvolvesTypeVariables) continue;
// If this and another type variable occur, this result involves
// type variables.
findInferrableTypeVars(cs.simplifyType(constraint->getSecondType()),
typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
continue;
}
@@ -904,15 +1002,29 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
kind = AllowedBindingKind::Supertypes;
} else {
// Can't infer anything.
if (!result.InvolvesTypeVariables)
ConstraintSystem::typeVarOccursInType(typeVar, first,
&result.InvolvesTypeVariables);
if (!result.InvolvesTypeVariables)
ConstraintSystem::typeVarOccursInType(typeVar, second,
&result.InvolvesTypeVariables);
if (result.InvolvesTypeVariables) continue;
// Check whether both this type and another type variable are
// inferrable.
SmallPtrSet<TypeVariableType *, 4> typeVars;
findInferrableTypeVars(first, typeVars);
findInferrableTypeVars(second, typeVars);
if (typeVars.size() > 1 && typeVars.count(typeVar))
result.InvolvesTypeVariables = true;
continue;
}
// 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;
@@ -1107,6 +1219,15 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
}
}
// If there were both dependent-member and non-dependent-member relational
// constraints, consider this "fully bound"; we don't want to touch it.
if (hasDependentMemberRelationalConstraints) {
if (hasNonDependentMemberRelationalConstraints)
result.FullyBound = true;
else
result.Bindings.clear();
}
return result;
}
@@ -2157,6 +2278,11 @@ bool ConstraintSystem::solveSimplified(
if (!bindings)
continue;
if (TC.getLangOpts().DebugConstraintSolver) {
auto &log = getASTContext().TypeCheckerDebug->getStream();
bindings.dump(typeVar, log, solverState->depth * 2);
}
// If these are the first bindings, or they are better than what
// we saw before, use them instead.
if (!bestTypeVar || bindings < bestBindings) {
+2 -123
View File
@@ -215,19 +215,6 @@ void ConstraintGraphNode::removeFixedBinding(TypeVariableType *typeVar) {
});
}
TypeVariableType *
ConstraintGraphNode::getMemberType(Identifier name,
std::function<TypeVariableType *()> create) {
auto known = MemberTypeIndex.find(name);
if (known != MemberTypeIndex.end())
return MemberTypes[known->second].second;
auto memberType = create();
MemberTypeIndex.insert({name, MemberTypes.size()});
MemberTypes.push_back({name, memberType});
return memberType;
}
#pragma mark Graph scope management
ConstraintGraphScope::ConstraintGraphScope(ConstraintGraph &CG)
: CG(CG), ParentScope(CG.ActiveScope), NumChanges(CG.Changes.size())
@@ -292,16 +279,6 @@ ConstraintGraph::Change::boundTypeVariable(TypeVariableType *typeVar,
return result;
}
ConstraintGraph::Change
ConstraintGraph::Change::addedMemberType(TypeVariableType *typeVar,
Identifier name) {
Change result;
result.Kind = ChangeKind::AddedMemberType;
result.MemberType.TypeVar = typeVar;
result.MemberType.Name = name;
return result;
}
void ConstraintGraph::Change::undo(ConstraintGraph &cg) {
/// Temporarily change the active scope to null, so we don't record
/// any changes made while performing the undo operation.
@@ -332,27 +309,6 @@ void ConstraintGraph::Change::undo(ConstraintGraph &cg) {
case ChangeKind::BoundTypeVariable:
cg.unbindTypeVariable(Binding.TypeVar, Binding.FixedType);
break;
case ChangeKind::AddedMemberType: {
auto &node = cg[MemberType.TypeVar];
// Erase the member type entry from the
auto known = node.MemberTypeIndex.find(MemberType.Name);
assert(known != node.MemberTypeIndex.end() && "Constraint graph corrupted");
unsigned index = known->second;
node.MemberTypeIndex.erase(known);
// If this was not the last member type, swap it with the last
// member type.
if (index != node.MemberTypes.size()-1) {
node.MemberTypes[index] = node.MemberTypes.back();
node.MemberTypeIndex[node.MemberTypes[index].first] = index;
}
// Pop off the last member type.
node.MemberTypes.pop_back();
break;
}
}
}
@@ -424,21 +380,6 @@ void ConstraintGraph::removeConstraint(Constraint *constraint) {
Changes.push_back(Change::removedConstraint(constraint));
}
TypeVariableType *ConstraintGraph::getMemberType(
TypeVariableType *typeVar,
Identifier name,
std::function<TypeVariableType *()> create) {
auto repTypeVar = CS.getRepresentative(typeVar);
auto &node = (*this)[repTypeVar];
return node.getMemberType(name, [&]() {
auto memberTypeVar = create();
if (ActiveScope)
Changes.push_back(Change::addedMemberType(repTypeVar, name));
return memberTypeVar;
});
}
void ConstraintGraph::mergeNodes(TypeVariableType *typeVar1,
TypeVariableType *typeVar2) {
assert(CS.getRepresentative(typeVar1) == CS.getRepresentative(typeVar2) &&
@@ -462,44 +403,6 @@ void ConstraintGraph::mergeNodes(TypeVariableType *typeVar1,
// Merge equivalence class from the non-representative type variable.
auto &nonRepNode = (*this)[typeVarNonRep];
repNode.addToEquivalenceClass(nonRepNode.getEquivalenceClassUnsafe());
// Merge member types.
for (auto newEquivTypeVar : nonRepNode.getEquivalenceClassUnsafe()) {
auto &newEquivNode = newEquivTypeVar == typeVarNonRep
? nonRepNode
: (*this)[newEquivTypeVar];
for (auto memberType : newEquivNode.MemberTypes) {
auto repKnown = repNode.MemberTypeIndex.find(memberType.first);
if (repKnown == repNode.MemberTypeIndex.end()) {
// We haven't seen this member type before. Add it.
repNode.MemberTypeIndex.insert({memberType.first,
repNode.MemberTypes.size()});
repNode.MemberTypes.push_back(memberType);
if (ActiveScope)
Changes.push_back(Change::addedMemberType(typeVarRep,
memberType.first));
continue;
}
// We have seen this member before. If the type variables are
// the same, do nothing. This is a fast-patch check.
auto repMemberTypeVar = repNode.MemberTypes[repKnown->second].second;
if (repMemberTypeVar == memberType.second)
continue;
// Find the representatives for the member type variables.
repMemberTypeVar = CS.getRepresentative(repMemberTypeVar);
auto otherMemberTypeVar = CS.getRepresentative(memberType.second);
// If the representatives are equivalent, do nothing.
if (repMemberTypeVar == otherMemberTypeVar)
continue;
// We have two different type variables representing the same
// member type; merge them.
CS.mergeEquivalenceClasses(repMemberTypeVar, otherMemberTypeVar);
}
}
}
void ConstraintGraph::bindTypeVariable(TypeVariableType *typeVar, Type fixed) {
@@ -513,6 +416,8 @@ void ConstraintGraph::bindTypeVariable(TypeVariableType *typeVar, Type fixed) {
auto &node = (*this)[typeVar];
for (auto otherTypeVar : typeVars) {
if (knownTypeVars.insert(otherTypeVar).second) {
if (typeVar == otherTypeVar) continue;
(*this)[otherTypeVar].addFixedBinding(typeVar);
node.addFixedBinding(otherTypeVar);
}
@@ -925,19 +830,6 @@ void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent) {
}
out << "\n";
}
// Print member types.
if (!MemberTypes.empty()) {
out.indent(indent + 2);
out << "Member types:\n";
for (auto memberType : MemberTypes) {
out.indent(indent + 4);
out << memberType.first.str() << " -> ";
memberType.second->print(out);
out << "\n";
}
out << "\n";
}
}
void ConstraintGraphNode::dump() {
@@ -1030,11 +922,6 @@ static void printValue(llvm::raw_ostream &os, unsigned value) {
os << value;
}
/// Print an identifier value.
static void printValue(llvm::raw_ostream &os, Identifier value) {
os << value.str();
}
void ConstraintGraphNode::verify(ConstraintGraph &cg) {
#define require(condition, complaint) _require(condition, complaint, cg, this)
#define requireWithContext(condition, complaint, context) \
@@ -1071,14 +958,6 @@ void ConstraintGraphNode::verify(ConstraintGraph &cg) {
"adjacency information has higher degree than # of constraints");
}
// Verify that the member types haven't gotten out of sync.
for (auto index : MemberTypeIndex) {
require(index.second < MemberTypes.size(),
"member type index out-of-range");
requireSameValue(index.first, MemberTypes[index.second].first,
"member type index map provides wrong index into vector");
}
// Based on the constraints we have, build up a representation of what
// we expect the adjacencies to look like.
llvm::DenseMap<TypeVariableType *, unsigned> expectedAdjacencies;
-47
View File
@@ -122,16 +122,6 @@ private:
/// Remove a type variable from the fixed-binding relationship.
void removeFixedBinding(TypeVariableType *typeVar);
/// Retrieves the member type of this type variable that corresponds
/// to the given name.
///
/// \param name The name of the type member.
///
/// \param create If the member does not already exist, this
/// callback will be invoked to create it.
TypeVariableType *getMemberType(Identifier name,
std::function<TypeVariableType *()> create);
/// The type variable this node represents.
TypeVariableType *TypeVar;
@@ -158,14 +148,6 @@ private:
/// are representatives of their equivalence classes.
mutable SmallVector<TypeVariableType *, 2> EquivalenceClass;
/// A set of (name, type variable) pairs representing the member types of
/// the given type variable.
llvm::SmallVector<std::pair<Identifier, TypeVariableType *>, 2> MemberTypes;
/// A mapping from the names of members of this type variable to an
/// index into the \c MemberTypes vector.
llvm::SmallDenseMap<Identifier, unsigned> MemberTypeIndex;
/// Print this graph node.
void print(llvm::raw_ostream &out, unsigned indent);
@@ -217,22 +199,6 @@ public:
/// Remove a constraint from the graph.
void removeConstraint(Constraint *constraint);
/// Retrieves the member type of a type variable that corresponds to
/// the given name.
///
/// \param typeVar The type variable.
///
/// \param name The name of the type member.
///
/// \param create If the member does not already exist, this
/// callback will be invoked to create it.
///
/// \returns the type variable representing the named member of the
/// given type variable.
TypeVariableType *getMemberType(TypeVariableType *typeVar,
Identifier name,
std::function<TypeVariableType *()> create);
/// Merge the two nodes for the two given type variables.
///
/// The type variables must actually have been merged already; this
@@ -335,8 +301,6 @@ private:
ExtendedEquivalenceClass,
/// Added a fixed binding for a type variable.
BoundTypeVariable,
/// Added a member type.
AddedMemberType
};
/// A change made to the constraint graph.
@@ -366,14 +330,6 @@ private:
/// The fixed type to which the type variable was bound.
TypeBase *FixedType;
} Binding;
struct {
/// The type variable whose member type was created.
TypeVariableType *TypeVar;
/// The name of the member.
Identifier Name;
} MemberType;
};
public:
@@ -395,9 +351,6 @@ private:
/// Create a change that bound a type variable to a fixed type.
static Change boundTypeVariable(TypeVariableType *typeVar, Type fixed);
/// Create a change that added a member type with the given name.
static Change addedMemberType(TypeVariableType *typeVar, Identifier name);
/// Undo this change, reverting the constraint graph to the state it
/// had prior to this change.
///
+118 -106
View File
@@ -26,12 +26,7 @@ using namespace constraints;
ConstraintSystem::ConstraintSystem(TypeChecker &tc, DeclContext *dc,
ConstraintSystemOptions options)
: TC(tc), DC(dc), Options(options),
Arena(tc.Context, Allocator,
[&](TypeVariableType *baseTypeVar, AssociatedTypeDecl *assocType) {
return getMemberType(baseTypeVar, assocType,
ConstraintLocatorBuilder(nullptr),
/*options=*/0);
}),
Arena(tc.Context, Allocator),
CG(*new ConstraintGraph(*this))
{
assert(DC && "context required");
@@ -348,102 +343,21 @@ ConstraintLocator *ConstraintSystem::getConstraintLocator(
return getConstraintLocator(anchor, path, builder.getSummaryFlags());
}
TypeVariableType *
ConstraintSystem::getMemberType(TypeVariableType *baseTypeVar,
AssociatedTypeDecl *assocType,
ConstraintLocatorBuilder locator,
unsigned options) {
return CG.getMemberType(baseTypeVar, assocType->getName(), [&]() {
// FIXME: Premature associated type -> identifier mapping. We should
// retain the associated type throughout.
auto loc = getConstraintLocator(locator);
auto memberTypeVar = createTypeVariable(loc, options);
addTypeMemberConstraint(baseTypeVar, assocType->getName(),
memberTypeVar, loc);
return memberTypeVar;
});
}
namespace {
/// Function object that retrieves a type variable corresponding to the
/// given dependent type.
class GetTypeVariable {
ConstraintSystem &CS;
ConstraintGraph &CG;
ConstraintLocatorBuilder &Locator;
public:
GetTypeVariable(ConstraintSystem &cs,
ConstraintLocatorBuilder &locator)
: CS(cs), CG(CS.getConstraintGraph()), Locator(locator) {}
TypeVariableType *operator()(Type base, AssociatedTypeDecl *member) {
// FIXME: Premature associated type -> identifier mapping. We should
// retain the associated type throughout.
auto baseTypeVar = base->castTo<TypeVariableType>();
return CG.getMemberType(baseTypeVar, member->getName(),
[&]() -> TypeVariableType* {
auto implArchetype = baseTypeVar->getImpl().getArchetype();
if (!implArchetype) {
// If the base type variable doesn't have an associated archetype,
// just form the member constraint.
// FIXME: Additional requirements?
auto locator = CS.getConstraintLocator(
Locator.withPathElement(member));
auto memberTypeVar = CS.createTypeVariable(locator,
TVO_PrefersSubtypeBinding);
CS.addTypeMemberConstraint(baseTypeVar, member->getName(),
memberTypeVar, locator);
return memberTypeVar;
}
ArchetypeType::NestedType nestedType;
ArchetypeType* archetype = nullptr;
if (implArchetype->hasNestedType(member->getName())) {
nestedType = implArchetype->getNestedType(member->getName());
archetype = nestedType.getValue()->getAs<ArchetypeType>();
}
ConstraintLocator *locator;
if (archetype) {
locator = CS.getConstraintLocator(
Locator.withPathElement(LocatorPathElt(archetype)));
} else {
// FIXME: Occurs when the nested type is a concrete type,
// in which case it's quite silly to create a type variable at all.
locator = CS.getConstraintLocator(Locator.withPathElement(member));
}
auto memberTypeVar = CS.createTypeVariable(locator,
TVO_PrefersSubtypeBinding);
// Bind the member's type variable as a type member of the base.
CS.addTypeMemberConstraint(baseTypeVar, member->getName(),
memberTypeVar, locator);
return memberTypeVar;
});
}
};
/// Function object that replaces all occurrences of archetypes and
/// dependent types with type variables.
class ReplaceDependentTypes {
ConstraintSystem &cs;
ConstraintLocatorBuilder &locator;
llvm::DenseMap<CanType, TypeVariableType *> &replacements;
GetTypeVariable &getTypeVariable;
llvm::DenseMap<CanType, Type> dependentMemberReplacements;
public:
ReplaceDependentTypes(
ConstraintSystem &cs,
ConstraintLocatorBuilder &locator,
llvm::DenseMap<CanType, TypeVariableType *> &replacements,
GetTypeVariable &getTypeVariable)
: cs(cs), locator(locator), replacements(replacements),
getTypeVariable(getTypeVariable) { }
llvm::DenseMap<CanType, TypeVariableType *> &replacements)
: cs(cs), locator(locator), replacements(replacements) { }
Type operator()(Type type) {
// Swift only supports rank-1 polymorphism.
@@ -469,15 +383,19 @@ namespace {
// member of its base type.
if (auto dependentMember = type->getAs<DependentMemberType>()) {
// Check whether we've already dealt with this dependent member.
auto known = replacements.find(dependentMember->getCanonicalType());
if (known != replacements.end())
auto known = dependentMemberReplacements.find(
dependentMember->getCanonicalType());
if (known != dependentMemberReplacements.end())
return known->second;
// Replace archetypes in the base type.
// FIXME: Tracking the dependent members seems unnecessary.
if (auto base =
((*this)(dependentMember->getBase()))->getAs<TypeVariableType>()) {
auto result = getTypeVariable(base, dependentMember->getAssocType());
replacements[dependentMember->getCanonicalType()] = result;
auto result =
DependentMemberType::get(base, dependentMember->getAssocType());
dependentMemberReplacements[dependentMember->getCanonicalType()] =
result;
return result;
}
}
@@ -538,10 +456,7 @@ Type ConstraintSystem::openType(
Type startingType,
ConstraintLocatorBuilder locator,
llvm::DenseMap<CanType, TypeVariableType *> &replacements) {
GetTypeVariable getTypeVariable{*this, locator};
ReplaceDependentTypes replaceDependentTypes(*this, locator, replacements,
getTypeVariable);
ReplaceDependentTypes replaceDependentTypes(*this, locator, replacements);
return startingType.transform(replaceDependentTypes);
}
@@ -675,6 +590,7 @@ Type ConstraintSystem::getFixedTypeRecursive(Type type,
TypeMatchOptions &flags,
bool wantRValue,
bool retainParens) {
if (wantRValue)
type = type->getRValueType();
@@ -686,17 +602,39 @@ Type ConstraintSystem::getFixedTypeRecursive(Type type,
}
}
while (auto typeVar = type->getAs<TypeVariableType>()) {
if (auto fixed = getFixedType(typeVar)) {
if (wantRValue)
fixed = fixed->getRValueType();
while (true) {
if (auto depMemType = type->getAs<DependentMemberType>()) {
if (!depMemType->getBase()->isTypeVariableOrMember()) return type;
type = fixed;
// FIXME: Perform a more limited simplification?
Type newType = simplifyType(type);
if (newType.getPointer() == type.getPointer()) return type;
if (wantRValue)
newType = newType->getRValueType();
type = newType;
// Once we've simplified a dependent member type, we need to generate a
// new constraint.
flags |= TMF_GenerateConstraints;
continue;
}
if (auto typeVar = type->getAs<TypeVariableType>()) {
if (auto fixed = getFixedType(typeVar)) {
if (wantRValue)
fixed = fixed->getRValueType();
type = fixed;
continue;
}
break;
}
break;
}
return type;
}
@@ -983,9 +921,7 @@ void ConstraintSystem::openGeneric(
replacements[gp->getCanonicalType()] = typeVar;
}
GetTypeVariable getTypeVariable{*this, locator};
ReplaceDependentTypes replaceDependentTypes(*this, locator, replacements,
getTypeVariable);
ReplaceDependentTypes replaceDependentTypes(*this, locator, replacements);
// Remember that any new constraints generated by opening this generic are
// due to the opening.
@@ -1569,6 +1505,51 @@ Type ConstraintSystem::simplifyType(Type type) {
return tvt;
}
// If this is a dependent member type for which we end up simplifying
// the base to a non-type-variable, perform lookup.
if (auto depMemTy = type->getAs<DependentMemberType>()) {
// Simplify the base.
Type newBase = simplifyType(depMemTy->getBase());
if (!newBase) return type;
// If nothing changed, we're done.
if (newBase.getPointer() == depMemTy->getBase().getPointer())
return type;
Type lookupBaseType = newBase;
// Look through an inout type.
if (auto inout = lookupBaseType->getAs<InOutType>())
lookupBaseType = inout->getObjectType();
// Look through a metatype.
if (auto metatype = lookupBaseType->getAs<AnyMetatypeType>())
lookupBaseType = metatype->getInstanceType();
// If the new base is still something we can't handle, just build a
// new dependent member type.
if (lookupBaseType->is<TypeVariableType>() ||
lookupBaseType->is<UnresolvedType>()) {
if (auto assocType = depMemTy->getAssocType())
return DependentMemberType::get(newBase, assocType);
else
return DependentMemberType::get(newBase, assocType);
}
// Dependent member types should only be created for associated types.
auto assocType = depMemTy->getAssocType();
assert(depMemTy->getAssocType());
auto result = lookupBaseType->getTypeOfMember(
DC->getParentModule(), assocType, &TC,
assocType->getDeclaredInterfaceType());
// FIXME: Record failure somehow?
if (!result) return type;
return result;
}
// If this is a FunctionType and we inferred new function attributes, apply
// them.
if (auto ft = dyn_cast<FunctionType>(type.getPointer())) {
@@ -1589,6 +1570,7 @@ Type ConstraintSystem::simplifyType(Type type) {
}
Type Solution::simplifyType(TypeChecker &tc, Type type) const {
// FIXME: Nearly identical to ConstraintSystem::simplifyType().
return type.transform([&](Type type) -> Type {
if (auto tvt = dyn_cast<TypeVariableType>(type.getPointer())) {
auto known = typeBindings.find(tvt);
@@ -1596,6 +1578,36 @@ Type Solution::simplifyType(TypeChecker &tc, Type type) const {
return known->second;
}
// If this is a dependent member type for which we end up simplifying
// the base to a non-type-variable, perform lookup.
if (auto depMemTy = type->getAs<DependentMemberType>()) {
// Simplify the base.
Type newBase = simplifyType(tc, depMemTy->getBase());
if (!newBase) return type;
// If nothing changed, we're done.
if (newBase.getPointer() == depMemTy->getBase().getPointer())
return type;
Type lookupBaseType = newBase;
// Look through an inout type.
if (auto inout = lookupBaseType->getAs<InOutType>())
lookupBaseType = inout->getObjectType();
// Look through a metatype.
if (auto metatype = lookupBaseType->getAs<AnyMetatypeType>())
lookupBaseType = metatype->getInstanceType();
// Dependent member types should only be created for associated types.
auto assocType = depMemTy->getAssocType();
assert(depMemTy->getAssocType());
return lookupBaseType->getTypeOfMember(
getConstraintSystem().DC->getParentModule(), assocType, &tc,
assocType->getDeclaredInterfaceType());
}
// If this is a FunctionType and we inferred new function attributes, apply
// them.
if (auto ft = dyn_cast<FunctionType>(type.getPointer())) {
+1 -24
View File
@@ -1203,12 +1203,7 @@ public:
/// \brief Create a new type variable.
TypeVariableType *createTypeVariable(ConstraintLocator *locator,
unsigned options) {
auto tv = TypeVariableType::getNew(TC.Context, assignTypeVariableID(),
locator, options);
addTypeVariable(tv);
return tv;
}
unsigned options);
/// Retrieve the set of active type variables.
ArrayRef<TypeVariableType *> getTypeVariables() const {
@@ -1477,24 +1472,6 @@ public:
InactiveConstraints.erase(constraint);
}
/// Retrieve the type that corresponds to the given member of the
/// given base type, which may be a newly-created type variable.
///
/// \param baseTypeVar The base type variable whose member is being queried.
///
/// \param assocType The associated type we're referencing.
///
/// \param locator The location used to describe this member access.
///
/// \param options Options to be supplied to type variable creation if
/// a new type is created.
///
/// \returns the type variable representing the member type.
TypeVariableType *getMemberType(TypeVariableType *baseTypeVar,
AssociatedTypeDecl *assocType,
ConstraintLocatorBuilder locator,
unsigned options);
/// Retrieve the list of inactive constraints.
ConstraintList &getConstraints() { return InactiveConstraints; }
+25 -14
View File
@@ -2023,28 +2023,39 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
//
// We will diagnose it later.
if (!sequenceType->isExistentialType()) {
auto member = cs.TC.lookupMemberType(cs.DC,
sequenceType,
tc.Context.Id_Iterator,
lookupOptions);
if (member) {
iteratorType = member.front().second;
ASTContext &ctx = tc.Context;
auto iteratorAssocType =
cast<AssociatedTypeDecl>(
sequenceProto->lookupDirect(ctx.Id_Iterator).front());
member = cs.TC.lookupMemberType(cs.DC,
iteratorType,
tc.Context.Id_Element,
lookupOptions);
iteratorType = sequenceType->getTypeOfMember(
cs.DC->getParentModule(),
iteratorAssocType,
&tc,
iteratorAssocType->getDeclaredInterfaceType());
if (member)
elementType = member.front().second;
if (iteratorType) {
auto iteratorProto =
tc.getProtocol(Stmt->getForLoc(),
KnownProtocolKind::IteratorProtocol);
if (!iteratorProto)
return true;
auto elementAssocType =
cast<AssociatedTypeDecl>(
iteratorProto->lookupDirect(ctx.Id_Element).front());
elementType = iteratorType->getTypeOfMember(
cs.DC->getParentModule(),
elementAssocType,
&tc,
elementAssocType->getDeclaredInterfaceType());
}
}
// If the type lookup failed, just add some constraints we can
// try to solve later.
if (elementType.isNull()) {
// Determine the iterator type of the sequence.
iteratorType = cs.createTypeVariable(Locator, /*options=*/0);
cs.addTypeMemberConstraint(SequenceType, tc.Context.Id_Iterator,
+14
View File
@@ -158,3 +158,17 @@ func joinWithNil(s: String) {
let a4 = [nil, "hello"]
let _: Int = a4 // expected-error{{value of type '[String?]'}}
}
struct OptionSetLike : ExpressibleByArrayLiteral {
typealias Element = OptionSetLike
init() { }
init(arrayLiteral elements: OptionSetLike...) { }
static let option: OptionSetLike = OptionSetLike()
}
func testOptionSetLike(b: Bool) {
let _: OptionSetLike = [ b ? [] : OptionSetLike.option, OptionSetLike.option]
let _: OptionSetLike = [ b ? [] : .option, .option]
}
+1 -1
View File
@@ -286,7 +286,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 {{contextual closure type '(Int, Int) -> Bool' expects 2 arguments, but 1 was used in closure body}}
+4 -12
View File
@@ -93,7 +93,7 @@ func <(lhs: IntWrapper, rhs: IntWrapper) -> Bool {
prefix func ***(lhs: IntWrapper) {}
// This is provided as an operator but not implemented here.
prefix operator ^^^ {}
prefix operator ^^^
// CHECK-DAG: "ClassFromOtherFile"
class Subclass : ClassFromOtherFile {}
@@ -126,9 +126,9 @@ protocol ExpressibleByExtraFloatLiteral
private protocol ExpressibleByExtraCharLiteral : ExpressibleByUnicodeScalarLiteral {
}
prefix operator ~~~ {}
prefix operator ~~~
protocol ThreeTilde {
prefix func ~~~(lhs: Self)
prefix static func ~~~(lhs: Self)
}
private struct ThreeTildeTypeImpl : ThreeTilde {
@@ -141,7 +141,7 @@ func overloadedOnProto<T: ThreeTilde>(_: T) {}
private prefix func ~~~(_: ThreeTildeTypeImpl) {}
// CHECK-DAG: - "~~~~"
prefix operator ~~~~ {}
prefix operator ~~~~
protocol FourTilde {
prefix static func ~~~~(arg: Self)
}
@@ -405,13 +405,9 @@ struct Sentinel2 {}
// CHECK-DAG: - ["Ps25ExpressibleByFloatLiteral", ""]
// CHECK-DAG: - !private ["Ps33ExpressibleByUnicodeScalarLiteral", ""]
// CHECK-DAG: - !private ["Ps10Strideable", "Stride"]
// CHECK-DAG: - !private ["Sa", "Element"]
// CHECK-DAG: - !private ["Sa", "reduce"]
// CHECK-DAG: - !private ["Sb", "_getBuiltinLogicValue"]
// CHECK-DAG: - ["Sb", "InnerToBool"]
// CHECK-DAG: - !private ["Vs10Dictionary", "Key"]
// CHECK-DAG: - !private ["Vs10Dictionary", "Value"]
// CHECK-DAG: - !private ["V4main17OtherFileIntArray", "Iterator"]
// CHECK-DAG: - !private ["V4main17OtherFileIntArray", "deinit"]
// CHECK-DAG: - !private ["V4main18OtherFileOuterType", "InnerType"]
// CHECK-DAG: - !private ["VV4main18OtherFileOuterType9InnerType", "init"]
@@ -419,9 +415,7 @@ struct Sentinel2 {}
// CHECK-DAG: - !private ["VV4main26OtherFileSecretTypeWrapper10SecretType", "constant"]
// CHECK-DAG: - !private ["V4main25OtherFileProtoImplementor", "deinit"]
// CHECK-DAG: - !private ["V4main26OtherFileProtoImplementor2", "deinit"]
// CHECK-DAG: - !private ["Vs13EmptyIterator", "Element"]
// CHECK-DAG: - !private ["Vs13EmptyIterator", "init"]
// CHECK-DAG: - !private ["Vs16IndexingIterator", "Element"]
// CHECK-DAG: - ["O4main13OtherFileEnum", "Value"]
// CHECK-DAG: - !private ["V4main20OtherFileEnumWrapper", "Enum"]
@@ -451,7 +445,6 @@ struct Sentinel2 {}
// CHECK-DAG: !private "Ps10Strideable"
// CHECK-DAG: !private "Sa"
// CHECK-DAG: - "Sb"
// CHECK-DAG: !private "Vs10Dictionary"
// CHECK-DAG: !private "V4main17OtherFileIntArray"
// CHECK-DAG: !private "V4main18OtherFileOuterType"
// CHECK-DAG: !private "VV4main18OtherFileOuterType9InnerType"
@@ -459,7 +452,6 @@ struct Sentinel2 {}
// CHECK-DAG: !private "V4main25OtherFileProtoImplementor"
// CHECK-DAG: !private "V4main26OtherFileProtoImplementor2"
// CHECK-DAG: !private "Vs13EmptyIterator"
// CHECK-DAG: !private "Vs16IndexingIterator"
// CHECK-DAG: - "O4main13OtherFileEnum"
// CHECK-DAG: !private "V4main20OtherFileEnumWrapper"
// CHECK-DAG: !private "V4main20OtherFileEnumWrapper"
+1 -1
View File
@@ -221,7 +221,7 @@ func testP4(_ s4a: S4a, s4b: S4b, s4c: S4c, s4d: S4d) {
s4c.extP4Int() // okay
var b1 = s4d.extP4a() // okay, "Bool" version
b1 = true // checks type above
s4d.extP4Int() // expected-error{{'Int' is not convertible to 'S4d.AssocP4' (aka 'Bool')}}
s4d.extP4Int() // expected-error{{'Bool' is not convertible to 'Int'}}
_ = b1
}
+1 -1
View File
@@ -235,7 +235,7 @@ struct WrongIsEqual : IsEqualComparable { // expected-error{{type 'WrongIsEqual'
//===----------------------------------------------------------------------===//
func existentialSequence(_ e: Sequence) { // expected-error{{has Self or associated type requirements}}
var x = e.makeIterator() // expected-error{{'Sequence' is not convertible to '<<error type>>'}}
var x = e.makeIterator() // expected-error{{'Sequence' is not convertible to 'Sequence.Iterator'}}
x.next()
x.nonexistent()
}
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend %s -parse -verify
var d = [String:String]()
_ = "\(d.map{ [$0 : $0] })" // expected-error {{type of expression is ambiguous without more context}}
_ = "\(d.map{ [$0 : $0] })" // expected-error {{contextual closure type specifies '(key: String, value: String)', but 1 was used in closure body, try adding extra parentheses around the single tuple argument}}
@@ -5,5 +5,5 @@
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
// RUN: not --crash %target-swift-frontend %s -parse
// RUN: not %target-swift-frontend %s -parse
func f<T{{if true as[T.h
@@ -5,6 +5,5 @@
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
// RUN: not --crash %target-swift-frontend %s -parse
// REQUIRES: asserts
// RUN: not %target-swift-frontend %s -parse
func a<T{if let a<T:T.h{
@@ -65,9 +65,8 @@ struct GoodIndexable : Indexable {
}
// expected-warning@+3 {{'Indexable' is deprecated: it will be removed in Swift 4.0. Please use 'Collection' instead}}
// expected-error@+2 {{type 'BadIndexable1' does not conform to protocol '_IndexableBase'}}
// expected-error@+1 {{type 'BadIndexable1' does not conform to protocol '_Indexable'}}
// expected-warning@+2 {{'Indexable' is deprecated: it will be removed in Swift 4.0. Please use 'Collection' instead}}
// expected-error@+1 {{type 'BadIndexable1' does not conform to protocol '_IndexableBase'}}
struct BadIndexable1 : Indexable {
func index(after i: Int) -> Int { return i + 1 }
var startIndex: Int { return 0 }