Skip to content

[CodeCompletion] Don't distinguish convertible and identical type relation #42211

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
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
20 changes: 4 additions & 16 deletions include/swift/IDE/CodeCompletionResultType.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,10 @@ enum class CodeCompletionResultTypeRelation : uint8_t {
/// The result's type is invalid at the expected position.
Invalid,

/// The result's type is convertible to the type of the expected.
/// The result's type is convertible or identical to the type of the expected.
Convertible,

/// The result's type is identical to the type of the expected.
Identical,

MAX_VALUE = Identical
MAX_VALUE = Convertible
};

class USRBasedType;
Expand Down Expand Up @@ -145,23 +142,14 @@ class USRBasedTypeContext {
/// convertible.
llvm::SmallVector<const USRBasedType *, 1> Types;

/// Whether a match against this type should be considered convertible
/// instead of identical. This is used to model optional conversions.
/// If we have
/// let x: Int? = #^COMPLETE^#
/// we add both 'Int?' and 'Int' as contextual types to the
/// USRBasedTypeContext, but an identical match against 'Int' should only
/// be considered convertible.
bool IsConvertible;

public:
/// Compute the type relation of \p ResultType to this conextual type.
CodeCompletionResultTypeRelation
typeRelation(const USRBasedType *ResultType,
const USRBasedType *VoidType) const;

ContextualType(ArrayRef<const USRBasedType *> Types, bool IsConvertible)
: Types(Types.begin(), Types.end()), IsConvertible(IsConvertible) {
ContextualType(ArrayRef<const USRBasedType *> Types)
: Types(Types.begin(), Types.end()) {
assert(!Types.empty() && "USRBasedTypeContext::ContextualType should "
"contain at least one type");
}
Expand Down
3 changes: 0 additions & 3 deletions lib/IDE/CodeCompletionResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,9 +490,6 @@ void CodeCompletionResult::printPrefix(raw_ostream &OS) const {
case CodeCompletionResultTypeRelation::Invalid:
Prefix.append("/TypeRelation[Invalid]");
break;
case CodeCompletionResultTypeRelation::Identical:
Prefix.append("/TypeRelation[Identical]");
break;
case CodeCompletionResultTypeRelation::Convertible:
Prefix.append("/TypeRelation[Convertible]");
break;
Expand Down
21 changes: 9 additions & 12 deletions lib/IDE/CodeCompletionResultType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,13 @@ USRBasedTypeContext::USRBasedTypeContext(const ExpectedTypeContext *TypeContext,
: Arena(Arena) {

for (auto possibleTy : TypeContext->getPossibleTypes()) {
ContextualTypes.emplace_back(USRBasedType::fromType(possibleTy, Arena),
/*IsConvertible=*/false);
ContextualTypes.emplace_back(USRBasedType::fromType(possibleTy, Arena));

// Add the unwrapped optional types as 'convertible' contextual types.
auto UnwrappedOptionalType = possibleTy->getOptionalObjectType();
while (UnwrappedOptionalType) {
ContextualTypes.emplace_back(
USRBasedType::fromType(UnwrappedOptionalType, Arena),
/*IsConvertible=*/true);
USRBasedType::fromType(UnwrappedOptionalType, Arena));
UnwrappedOptionalType = UnwrappedOptionalType->getOptionalObjectType();
}

Expand All @@ -57,7 +55,7 @@ USRBasedTypeContext::USRBasedTypeContext(const ExpectedTypeContext *TypeContext,
// Archetypes are also be used to model generic return types, in which
// case they don't have any conformsTo entries. We simply ignore those.
if (!USRTypes.empty()) {
ContextualTypes.emplace_back(USRTypes, /*IsConvertible=*/false);
ContextualTypes.emplace_back(USRTypes);
}
}
}
Expand All @@ -76,6 +74,9 @@ USRBasedTypeContext::typeRelation(const USRBasedType *ResultType) const {
TypeRelation Res = TypeRelation::Unknown;
for (auto &ContextualType : ContextualTypes) {
Res = std::max(Res, ContextualType.typeRelation(ResultType, VoidType));
if (Res == TypeRelation::MAX_VALUE) {
return Res; // We can't improve further
}
}
return Res;
}
Expand Down Expand Up @@ -105,7 +106,7 @@ TypeRelation USRBasedType::typeRelationImpl(
return TypeRelation::Unknown;
}
if (ResultType == this) {
return TypeRelation::Identical;
return TypeRelation::Convertible;
}
for (const USRBasedType *Supertype : ResultType->getSupertypes()) {
if (!VisitedTypes.insert(Supertype).second) {
Expand Down Expand Up @@ -239,14 +240,10 @@ TypeRelation USRBasedTypeContext::ContextualType::typeRelation(

/// Types is a conjunction, not a disjunction (see documentation on Types),
/// so we need to compute the minimum type relation here.
TypeRelation Result = TypeRelation::Identical;
TypeRelation Result = TypeRelation::Convertible;
for (auto ContextType : Types) {
Result = std::min(Result, ContextType->typeRelation(ResultType, VoidType));
}

if (IsConvertible && Result == TypeRelation::Identical) {
Result = TypeRelation::Convertible;
}
return Result;
}

Expand All @@ -262,7 +259,7 @@ static TypeRelation calculateTypeRelation(Type Ty, Type ExpectedTy,
// requirements – ignore them
if (!Ty->hasTypeParameter() && !ExpectedTy->hasTypeParameter()) {
if (Ty->isEqual(ExpectedTy))
return TypeRelation::Identical;
return TypeRelation::Convertible;
bool isAny = false;
isAny |= ExpectedTy->isAny();
isAny |= ExpectedTy->is<ArchetypeType>() &&
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/complete_accessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// NO_OBSERVER-NOT: willSet
// NO_OBSERVER-NOT: didSet

// WITH_GLOBAL: Decl[GlobalVar]/CurrModule{{(/TypeRelation\[Identical\])?}}: globalValue[#String#];
// WITH_GLOBAL: Decl[GlobalVar]/CurrModule{{(/TypeRelation\[Convertible\])?}}: globalValue[#String#];
// NO_GLOBAL-NOT: globalValue;

// WITH_SELF: Decl[LocalVar]/Local: self[#{{.+}}#]; name=self
Expand Down
6 changes: 3 additions & 3 deletions test/IDE/complete_after_super.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ extension SuperBaseA {
// COMMON_BASE_A_DOT: End completions

// COMMON_BASE_A_DOT_CONTEXT: Begin completions
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: baseInstanceVar[#Int#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: baseProp[#Int#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: baseInstanceVar[#Int#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: baseProp[#Int#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceMethod]/CurrNominal: baseFunc0()[#Void#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceMethod]/CurrNominal: baseFunc1({#(a): Int#})[#Void#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: baseExtProp[#Int#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: baseExtProp[#Int#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT-DAG: Decl[InstanceMethod]/CurrNominal: baseExtFunc0()[#Void#]{{; name=.+$}}
// COMMON_BASE_A_DOT_CONTEXT: End completions

Expand Down
Loading