Skip to content

Fix typealias used in associatedtype constraint #27987

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

Closed
wants to merge 2 commits into from
Closed
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
19 changes: 19 additions & 0 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#include "llvm/Support/SaveAndRestore.h"
#include <algorithm>

#include <iostream>

using namespace swift;
using llvm::DenseMap;

Expand Down Expand Up @@ -3625,6 +3627,8 @@ ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
Type type,
ArchetypeResolutionKind resolutionKind,
bool wantExactPotentialArchetype) {
type->dump();

// An error type is best modeled as an unresolved potential archetype, since
// there's no way to be sure what it is actually meant to be.
if (type->is<ErrorType>()) {
Expand All @@ -3633,19 +3637,24 @@ ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(

// The equivalence class of a generic type is known directly.
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
std::cout << "0" << std::endl;
unsigned index = GenericParamKey(genericParam).findIndexIn(
getGenericParams());
std::cout << "1" << std::endl;
if (index < Impl->GenericParams.size()) {
std::cout << "2" << std::endl;
return ResolvedType(Impl->PotentialArchetypes[index]);
}

std::cout << "3" << std::endl;
return ResolvedType::forUnresolved(nullptr);
}

// The equivalence class of a dependent member type is determined by its
// base equivalence class, if there is one.
if (auto depMemTy = type->getAs<DependentMemberType>()) {
// Find the equivalence class of the base.
std::cout << "4" << std::endl;
auto resolvedBase =
maybeResolveEquivalenceClass(depMemTy->getBase(),
resolutionKind,
Expand Down Expand Up @@ -4850,6 +4859,16 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirement(
FloatingRequirementSource source,
UnresolvedHandlingKind unresolvedHandling,
llvm::function_ref<void(Type, Type)> diagnoseMismatch) {

if (paOrT1.is<Type>())
paOrT1.get<Type>()->dump();
if (paOrT1.is<PotentialArchetype*>())
paOrT1.get<PotentialArchetype*>()->dump();

if (paOrT2.is<Type>())
paOrT2.get<Type>()->dump();
if (paOrT2.is<PotentialArchetype*>())
paOrT2.get<PotentialArchetype*>()->dump();

auto resolved1 = resolve(paOrT1, source);
if (!resolved1) {
Expand Down
29 changes: 24 additions & 5 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/SaveAndRestore.h"
#include <iostream>

using namespace swift;

Expand Down Expand Up @@ -566,8 +567,7 @@ Type TypeChecker::resolveTypeInContext(TypeDecl *typeDecl, DeclContext *foundDC,
if (selfType->is<GenericTypeParamType>()) {
if (typeDecl->getDeclContext()->getSelfProtocolDecl()) {
if (isa<AssociatedTypeDecl>(typeDecl) ||
(isa<TypeAliasDecl>(typeDecl) &&
!cast<TypeAliasDecl>(typeDecl)->isGeneric())) {
typeDecl->getAsGenericContext()) {
// FIXME: We should use this lookup method for the Interface
// stage too, but right now that causes problems with
// Sequence.SubSequence vs Collection.SubSequence; the former
Expand All @@ -576,10 +576,16 @@ Type TypeChecker::resolveTypeInContext(TypeDecl *typeDecl, DeclContext *foundDC,
// because we use the Sequence.SubSequence default instead of
// the Collection.SubSequence default, even when the conforming
// type wants to conform to Collection.
// selfType->dump();
// typeDecl->dump();
// std::cout << typeDecl->getName().get() << std::endl;

if (resolution.getStage() == TypeResolutionStage::Structural) {
return resolution.resolveSelfAssociatedType(selfType, foundDC,
typeDecl->getName());
} else if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
}

if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
typeDecl = assocType->getAssociatedTypeAnchor();
}
}
Expand Down Expand Up @@ -1295,10 +1301,23 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution,
// Otherwise, check for an ambiguity.
if (!resolution.areSameType(current, type)) {
isAmbiguous = true;
break;
// If a typealias collides with an associatedtype in generic requirement
// position, prefer the associated type.
if (options.getContext() == TypeResolverContext::GenericRequirement) {
if (isa<TypeAliasDecl>(currentDecl) && isa<AssociatedTypeDecl>(typeDecl)) {
current = type;
currentDecl = typeDecl;
currentDC = foundDC;
isAmbiguous = false;
} else if (isa<AssociatedTypeDecl>(currentDecl) &&
isa<TypeAliasDecl>(typeDecl)) {
isAmbiguous = false;
}
}
if (isAmbiguous) break;
}

// We have a found multiple type aliases that refer to the same thing.
// We have found multiple type aliases that refer to the same thing.
// Ignore the duplicate.
}

Expand Down
16 changes: 16 additions & 0 deletions validation-test/compiler_crashers_2_fixed/sr11639.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %target-typecheck-verify-swift

protocol ProtocolA {
associatedtype T1
}

struct S<T> : ProtocolA {
typealias T1 = T
}

protocol ProtocolB: ProtocolA {
associatedtype T2: ProtocolB where T2.T1 == T3.T1
associatedtype X
typealias T3 = S<X>
}