Skip to content

Drop witness markers for 'uninteresting' dependent types #5687

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 9 commits into from
Nov 9, 2016
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
12 changes: 12 additions & 0 deletions lib/AST/ArchetypeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2046,6 +2046,15 @@ Type ArchetypeBuilder::substDependentType(Type type) {
static void collectRequirements(ArchetypeBuilder &builder,
ArrayRef<GenericTypeParamType *> params,
SmallVectorImpl<Requirement> &requirements) {
// Don't emit WitnessMarker requirements for secondary types with
// no requirements.
auto dropRedundantWitnessMarker = [&]() {
if (!requirements.empty() &&
requirements.back().getKind() == RequirementKind::WitnessMarker &&
!requirements.back().getFirstType()->is<GenericTypeParamType>())
requirements.pop_back();
};

builder.enumerateRequirements([&](RequirementKind kind,
ArchetypeBuilder::PotentialArchetype *archetype,
llvm::PointerUnion<Type, ArchetypeBuilder::PotentialArchetype *> type,
Expand All @@ -2070,6 +2079,7 @@ static void collectRequirements(ArchetypeBuilder &builder,
return;

if (kind == RequirementKind::WitnessMarker) {
dropRedundantWitnessMarker();
requirements.push_back(Requirement(kind, depTy, Type()));
return;
}
Expand All @@ -2089,6 +2099,8 @@ static void collectRequirements(ArchetypeBuilder &builder,

requirements.push_back(Requirement(kind, depTy, repTy));
});

dropRedundantWitnessMarker();
}

GenericSignature *ArchetypeBuilder::getGenericSignature() {
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ SpecializedProtocolConformance::getTypeWitnessSubstAndDecl(
// Apply the substitution we computed above
auto specializedType
= genericWitness.getReplacement().subst(substitutionMap, None);
if (!specializedType)
specializedType = ErrorType::get(genericWitness.getReplacement());

// If the type witness was unchanged, just copy it directly.
if (specializedType.getPointer() == genericWitness.getReplacement().getPointer()) {
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2810,12 +2810,12 @@ static Type getMemberForBaseType(ConformanceSource conformances,
}

if (!conformance) return failed();
if (!conformance->isConcrete()) return failed();

// If we have an unsatisfied type witness while we're checking the
// conformances we're supposed to skip this conformance's unsatisfied type
// witnesses, and we have an unsatisfied type witness, return
// "missing".
assert(conformance->isConcrete());
if (conformance->getConcrete()->getRootNormalConformance()->getState()
== ProtocolConformanceState::CheckingTypeWitnesses &&
!conformance->getConcrete()->hasTypeWitness(assocType, nullptr))
Expand Down
30 changes: 3 additions & 27 deletions lib/SILOptimizer/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1332,28 +1332,6 @@ void ValueLifetimeAnalysis::dump() const {
// Casts Optimization and Simplification
//===----------------------------------------------------------------------===//

/// \brief Get a substitution corresponding to the type witness.
/// Inspired by ProtocolConformance::getTypeWitnessByName.
static const Substitution *
getTypeWitnessByName(ProtocolConformance *conformance, Identifier name) {
// Find the named requirement.
AssociatedTypeDecl *assocType = nullptr;
assert(conformance && "Missing conformance information");
auto members = conformance->getProtocol()->lookupDirect(name);
for (auto member : members) {
assocType = dyn_cast<AssociatedTypeDecl>(member);
if (assocType)
break;
}

if (!assocType)
return nullptr;

if (!conformance->hasTypeWitness(assocType, nullptr)) {
return nullptr;
}
return &conformance->getTypeWitness(assocType, nullptr);
}

/// Check if is a bridging cast, i.e. one of the sides is
/// a bridged type.
Expand Down Expand Up @@ -1513,14 +1491,12 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst,
SmallVector<SILValue, 1> Args;

// Add substitutions
SmallVector<Substitution, 2> Subs;
auto Conformances =
M.getASTContext().AllocateUninitialized<ProtocolConformanceRef>(1);
Conformances[0] = ProtocolConformanceRef(Conformance);
Subs.push_back(Substitution(Target, Conformances));
const Substitution *DepTypeSubst = getTypeWitnessByName(
Conformance, M.getASTContext().getIdentifier("_ObjectiveCType"));
Subs.push_back(*DepTypeSubst);
Substitution Subs[1] = {
Substitution(Target, Conformances)
};
auto SILFnTy = FuncRef->getType();
SILType SubstFnTy = SILFnTy.substGenericArgs(M, Subs);
SILType ResultTy = SubstFnTy.castTo<SILFunctionType>()->getSILResult();
Expand Down
23 changes: 3 additions & 20 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1573,26 +1573,9 @@ namespace {
auto fnGenericParams
= fn->getGenericSignatureOfContext()->getGenericParams();

SmallVector<Substitution, 2> Subs;
Substitution sub(valueType, Conformances);
Subs.push_back(sub);

// Add substitution for the dependent type T._ObjectiveCType.
if (conformsToBridgedToObjectiveC) {
auto objcTypeId = tc.Context.Id_ObjectiveCType;
auto objcAssocType = cast<AssociatedTypeDecl>(
conformance->getProtocol()->lookupDirect(
objcTypeId).front());
const Substitution &objcSubst = conformance->getTypeWitness(
objcAssocType, &tc);

// Create a substitution for the dependent type.
Substitution newDepTypeSubst(
objcSubst.getReplacement(),
objcSubst.getConformances());

Subs.push_back(newDepTypeSubst);
}
Substitution Subs[1] = {
Substitution(valueType, Conformances)
};

ConcreteDeclRef fnSpecRef(tc.Context, fn, Subs);
auto fnRef = new (tc.Context) DeclRefExpr(fnSpecRef,
Expand Down
4 changes: 3 additions & 1 deletion lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5436,7 +5436,9 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
if (calleeInfo.closeness == CC_ExactMatch)
return true;

if (!CS->getContextualType() || calleeInfo.closeness != CC_ArgumentMismatch)
if (!CS->getContextualType() ||
(calleeInfo.closeness != CC_ArgumentMismatch &&
calleeInfo.closeness != CC_OneGenericArgumentMismatch))
return false;

CalleeCandidateInfo candidates(fnExpr, hasTrailingClosure, CS);
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1438,11 +1438,11 @@ void TypeChecker::completePropertyBehaviorParameter(VarDecl *VD,

void TypeChecker::completePropertyBehaviorAccessors(VarDecl *VD,
VarDecl *ValueImpl,
Type valueTy,
ArrayRef<Substitution> SelfInterfaceSubs,
ArrayRef<Substitution> SelfContextSubs) {
auto selfTy = SelfContextSubs[0].getReplacement();
auto valueTy = SelfContextSubs[1].getReplacement();


SmallVector<ASTNode, 3> bodyStmts;

auto makeSelfExpr = [&](FuncDecl *fromAccessor,
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2382,7 +2382,7 @@ class ExprCleaner {
}

std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
TS->Patterns.insert({ P, P->getType() });
TS->Patterns.insert({ P, P->hasType() ? P->getType() : Type() });
return { true, P };
}

Expand Down
16 changes: 12 additions & 4 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2958,16 +2958,23 @@ static void checkVarBehavior(VarDecl *decl, TypeChecker &TC) {
TC.Context.AllocateUninitialized<ProtocolConformanceRef>(1);
auto selfConformance = new ((void*)conformanceMem.data())
ProtocolConformanceRef(conformance);
// FIXME: Additional associated types introduced by other requirements?
Substitution interfaceSubs[] = {
Substitution allInterfaceSubs[] = {
Substitution(behaviorInterfaceSelf, *selfConformance),
Substitution(decl->getInterfaceType(), valueSub.getConformances()),
};
Substitution contextSubs[] = {
Substitution allContextSubs[] = {
Substitution(behaviorSelf, *selfConformance),
Substitution(decl->getType(), valueSub.getConformances()),
};


ArrayRef<Substitution> interfaceSubs = allInterfaceSubs;
if (interfaceSubs.back().getConformances().empty())
interfaceSubs = interfaceSubs.drop_back();

ArrayRef<Substitution> contextSubs = allContextSubs;
if (contextSubs.back().getConformances().empty())
contextSubs = contextSubs.drop_back();

// Now that type witnesses are done, satisfy property and method requirements.
conformance->setState(ProtocolConformanceState::Checking);

Expand Down Expand Up @@ -3185,6 +3192,7 @@ static void checkVarBehavior(VarDecl *decl, TypeChecker &TC) {
// Synthesize the bodies of the property's accessors now, forwarding to the
// 'value' implementation.
TC.completePropertyBehaviorAccessors(decl, behavior->ValueDecl,
decl->getType(),
interfaceSubs, contextSubs);

return;
Expand Down
70 changes: 70 additions & 0 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1591,18 +1591,88 @@ namespace {
/// requirements.
SmallVector<std::tuple<AssociatedTypeDecl *, Type, CheckTypeWitnessResult>,
2> NonViable;

void dump(llvm::raw_ostream &out, unsigned indent) const {
out << "\n";
out.indent(indent) << "(";
if (Witness) {
Witness->dumpRef(out);
}

for (const auto &inferred : Inferred) {
out << "\n";
out.indent(indent + 2);
out << inferred.first->getName() << " := "
<< inferred.second.getString();
}

for (const auto &inferred : NonViable) {
out << "\n";
out.indent(indent + 2);
out << std::get<0>(inferred)->getName() << " := "
<< std::get<1>(inferred).getString();
if (auto nominal = std::get<2>(inferred).getProtocolOrClass())
out << " [failed constraint " << nominal->getName() << "]";
}

out << ")";
}

LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
"only for use in the debugger");
};

void InferredAssociatedTypesByWitness::dump() const {
dump(llvm::errs(), 0);
}

/// The set of witnesses that were considered when attempting to
/// infer associated types.
typedef SmallVector<InferredAssociatedTypesByWitness, 2>
InferredAssociatedTypesByWitnesses;

void dumpInferredAssociatedTypesByWitnesses(
const InferredAssociatedTypesByWitnesses &inferred,
llvm::raw_ostream &out,
unsigned indent) {
for (const auto &value : inferred) {
value.dump(out, indent);
}
}

void dumpInferredAssociatedTypesByWitnesses(
const InferredAssociatedTypesByWitnesses &inferred) LLVM_ATTRIBUTE_USED;

void dumpInferredAssociatedTypesByWitnesses(
const InferredAssociatedTypesByWitnesses &inferred) {
dumpInferredAssociatedTypesByWitnesses(inferred, llvm::errs(), 0);
}

/// A mapping from requirements to the set of matches with witnesses.
typedef SmallVector<std::pair<ValueDecl *,
InferredAssociatedTypesByWitnesses>, 4>
InferredAssociatedTypes;

void dumpInferredAssociatedTypes(const InferredAssociatedTypes &inferred,
llvm::raw_ostream &out,
unsigned indent) {
for (const auto &value : inferred) {
out << "\n";
out.indent(indent) << "(";
value.first->dumpRef(out);
dumpInferredAssociatedTypesByWitnesses(value.second, out, indent + 2);
out << ")";
}
out << "\n";
}

void dumpInferredAssociatedTypes(
const InferredAssociatedTypes &inferred) LLVM_ATTRIBUTE_USED;

void dumpInferredAssociatedTypes(const InferredAssociatedTypes &inferred) {
dumpInferredAssociatedTypes(inferred, llvm::errs(), 0);
}

/// The protocol conformance checker.
///
/// This helper class handles most of the details of checking whether a
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,7 @@ class TypeChecker final : public LazyResolver {
/// property.
void completePropertyBehaviorAccessors(VarDecl *VD,
VarDecl *ValueImpl,
Type valueTy,
ArrayRef<Substitution> SelfInterfaceSubs,
ArrayRef<Substitution> SelfContextSubs);

Expand Down
23 changes: 23 additions & 0 deletions stdlib/public/core/BidirectionalCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,29 @@ public protocol BidirectionalCollection
///
/// - Complexity: O(1)
var last: Iterator.Element? { get }

/// Accesses a contiguous subrange of the collection's elements.
///
/// The accessed slice uses the same indices for the same elements as the
/// original collection uses. Always use the slice's `startIndex` property
/// instead of assuming that its indices start at a particular value.
///
/// This example demonstrates getting a slice of an array of strings, finding
/// the index of one of the strings in the slice, and then using that index
/// in the original array.
///
/// let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
/// let streetsSlice = streets[2 ..< streets.endIndex]
/// print(streetsSlice)
/// // Prints "["Channing", "Douglas", "Evarts"]"
///
/// let index = streetsSlice.index(of: "Evarts") // 4
/// print(streets[index!])
/// // Prints "Evarts"
///
/// - Parameter bounds: A range of the collection's indices. The bounds of
/// the range must be valid indices of the collection.
subscript(bounds: Range<Index>) -> SubSequence { get }
}

/// Default implementation for bidirectional collections.
Expand Down
6 changes: 5 additions & 1 deletion stdlib/public/core/Indices.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ public struct ${Self}<
internal var _endIndex: Elements.Index
}

extension ${collectionForTraversal(Traversal)} where Indices == ${Self}<Self> {
extension ${collectionForTraversal(Traversal)}
% if Traversal != 'RandomAccess':
where Indices == ${Self}<Self>
% end
{
/// The indices that are valid for subscripting the collection, in ascending
/// order.
///
Expand Down
23 changes: 23 additions & 0 deletions stdlib/public/core/RandomAccessCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,29 @@ public protocol RandomAccessCollection :
/// }
/// // c == MyFancyCollection([2, 4, 6, 8, 10])
var indices: Indices { get }

/// Accesses a contiguous subrange of the collection's elements.
///
/// The accessed slice uses the same indices for the same elements as the
/// original collection uses. Always use the slice's `startIndex` property
/// instead of assuming that its indices start at a particular value.
///
/// This example demonstrates getting a slice of an array of strings, finding
/// the index of one of the strings in the slice, and then using that index
/// in the original array.
///
/// let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
/// let streetsSlice = streets[2 ..< streets.endIndex]
/// print(streetsSlice)
/// // Prints "["Channing", "Douglas", "Evarts"]"
///
/// let index = streetsSlice.index(of: "Evarts") // 4
/// print(streets[index!])
/// // Prints "Evarts"
///
/// - Parameter bounds: A range of the collection's indices. The bounds of
/// the range must be valid indices of the collection.
subscript(bounds: Range<Index>) -> SubSequence { get }
}

/// Supply the default "slicing" `subscript` for `RandomAccessCollection`
Expand Down
10 changes: 8 additions & 2 deletions test/Generics/associated_types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,23 @@ protocol A {
}

protocol B : A {
associatedtype e : A = C<Self> // expected-note {{default type 'C<C<a>>' for associated type 'e' (from protocol 'B') does not conform to 'A'}}
associatedtype e : A = C<Self>
}

extension B {
func c() {
}
}

struct C<a : B> : B { // expected-error {{type 'C<a>' does not conform to protocol 'B'}}
struct C<a : B> : B {
}

struct CC : B {
typealias e = CC
}

C<CC>().c()

// SR-511
protocol sr511 {
typealias Foo // expected-error {{typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement}}
Expand Down
Loading