Skip to content

Commit d042cdb

Browse files
committed
Sema: Diagnose invalid CustomAttrs using type resolution
Now that directReferencesForTypeRepr() no longer returns ambiguous results, move the special ambiguity diagnostic out of CustomAttrNominalRequest::evaluate(), and instead diagnose these situations in TypeCheckAttr.cpp. Special-case the 'unknown type' diagnostic though, to report 'unknown attribute' in the common case where the name lookup failed.
1 parent 22facd3 commit d042cdb

File tree

6 files changed

+47
-61
lines changed

6 files changed

+47
-61
lines changed

include/swift/AST/DiagnosticsCommon.def

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,6 @@ REMARK(remark_save_cache, none,
209209
// MARK: custom attribute diagnostics
210210
//------------------------------------------------------------------------------
211211

212-
ERROR(ambiguous_custom_attribute_ref,none,
213-
"ambiguous use of attribute %0", (Identifier))
214-
NOTE(ambiguous_custom_attribute_ref_fix,none,
215-
"use '%0.' to reference the attribute %1 in module %2",
216-
(StringRef, Identifier, Identifier))
217-
NOTE(found_attribute_candidate,none,
218-
"found this attribute", ())
219212
ERROR(unknown_attribute,none,
220213
"unknown attribute '%0'", (StringRef))
221214

lib/AST/NameLookup.cpp

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,54 +2618,6 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
26182618
}
26192619
}
26202620

2621-
// If we have more than one attribute declaration, we have an ambiguity.
2622-
// So, emit an ambiguity diagnostic.
2623-
if (auto typeRepr = attr->getTypeRepr()) {
2624-
if (nominals.size() > 1) {
2625-
SmallVector<NominalTypeDecl *, 4> ambiguousCandidates;
2626-
// Filter out declarations that cannot be attributes.
2627-
for (auto decl : nominals) {
2628-
if (isa<ProtocolDecl>(decl)) {
2629-
continue;
2630-
}
2631-
ambiguousCandidates.push_back(decl);
2632-
}
2633-
if (ambiguousCandidates.size() > 1) {
2634-
auto attrName = nominals.front()->getName();
2635-
ctx.Diags.diagnose(typeRepr->getLoc(),
2636-
diag::ambiguous_custom_attribute_ref, attrName);
2637-
for (auto candidate : ambiguousCandidates) {
2638-
ctx.Diags.diagnose(candidate->getLoc(),
2639-
diag::found_attribute_candidate);
2640-
// If the candidate is a top-level attribute, let's suggest
2641-
// adding module name to resolve the ambiguity.
2642-
if (candidate->getDeclContext()->isModuleScopeContext()) {
2643-
auto moduleName = candidate->getParentModule()->getName();
2644-
ctx.Diags
2645-
.diagnose(typeRepr->getLoc(),
2646-
diag::ambiguous_custom_attribute_ref_fix,
2647-
moduleName.str(), attrName, moduleName)
2648-
.fixItInsert(typeRepr->getLoc(), moduleName.str().str() + ".");
2649-
}
2650-
}
2651-
return nullptr;
2652-
}
2653-
}
2654-
}
2655-
2656-
// There is no nominal type with this name, so complain about this being
2657-
// an unknown attribute.
2658-
std::string typeName;
2659-
if (auto typeRepr = attr->getTypeRepr()) {
2660-
llvm::raw_string_ostream out(typeName);
2661-
typeRepr->print(out);
2662-
} else {
2663-
typeName = attr->getType().getString();
2664-
}
2665-
2666-
ctx.Diags.diagnose(attr->getLocation(), diag::unknown_attribute, typeName);
2667-
attr->setInvalid();
2668-
26692621
return nullptr;
26702622
}
26712623

lib/Sema/TypeCheckAttr.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2955,7 +2955,30 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
29552955
auto nominal = evaluateOrDefault(
29562956
Ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
29572957

2958+
// Diagnose errors.
29582959
if (!nominal) {
2960+
auto typeRepr = attr->getTypeRepr();
2961+
2962+
auto type = TypeResolution::forInterface(dc, TypeResolverContext::CustomAttr,
2963+
// Unbound generics and placeholders
2964+
// are not allowed within this
2965+
// attribute.
2966+
/*unboundTyOpener*/ nullptr,
2967+
/*placeholderHandler*/ nullptr)
2968+
.resolveType(typeRepr);
2969+
2970+
if (type->is<ErrorType>()) {
2971+
// Type resolution has failed, and we should have diagnosed something already.
2972+
assert(Ctx.hadError());
2973+
} else {
2974+
// Otherwise, something odd happened.
2975+
std::string typeName;
2976+
llvm::raw_string_ostream out(typeName);
2977+
typeRepr->print(out);
2978+
2979+
Ctx.Diags.diagnose(attr->getLocation(), diag::unknown_attribute, typeName);
2980+
}
2981+
29592982
attr->setInvalid();
29602983
return;
29612984
}

lib/Sema/TypeCheckType.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,14 @@ static Type diagnoseUnknownType(TypeResolution resolution,
10801080

10811081
// Unqualified lookup case.
10821082
if (parentType.isNull()) {
1083+
// Tailored diagnostic for custom attributes.
1084+
if (resolution.getOptions().is(TypeResolverContext::CustomAttr)) {
1085+
diags.diagnose(comp->getNameLoc(), diag::unknown_attribute,
1086+
comp->getNameRef().getBaseIdentifier().str());
1087+
1088+
return ErrorType::get(ctx);
1089+
}
1090+
10831091
if (comp->getNameRef().isSimpleName(ctx.Id_Self) &&
10841092
!isa<GenericIdentTypeRepr>(comp)) {
10851093
DeclContext *nominalDC = nullptr;
@@ -1642,6 +1650,15 @@ resolveIdentTypeComponent(TypeResolution resolution,
16421650
!options.is(TypeResolverContext::TypeAliasDecl)) {
16431651

16441652
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
1653+
// Tailored diagnostic for custom attributes.
1654+
if (options.is(TypeResolverContext::CustomAttr)) {
1655+
auto &ctx = resolution.getASTContext();
1656+
ctx.Diags.diagnose(lastComp->getNameLoc(), diag::unknown_attribute,
1657+
lastComp->getNameRef().getBaseIdentifier().str());
1658+
1659+
return ErrorType::get(ctx);
1660+
}
1661+
16451662
diagnoseUnboundGenericType(result,
16461663
lastComp->getNameLoc().getBaseNameLoc());
16471664
}
@@ -3605,6 +3622,7 @@ NeverNullType TypeResolver::resolveImplicitlyUnwrappedOptionalType(
36053622
case TypeResolverContext::AbstractFunctionDecl:
36063623
case TypeResolverContext::ClosureExpr:
36073624
case TypeResolverContext::Inherited:
3625+
case TypeResolverContext::CustomAttr:
36083626
doDiag = true;
36093627
break;
36103628
}

lib/Sema/TypeCheckType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ enum class TypeResolverContext : uint8_t {
133133

134134
/// Whether this is an "inherited" type.
135135
Inherited,
136+
137+
/// Whether this is a custom attribute.
138+
CustomAttr
136139
};
137140

138141
/// Options that determine how type resolution should work.
@@ -215,6 +218,7 @@ class TypeResolutionOptions {
215218
case Context::ImmediateOptionalTypeArgument:
216219
case Context::AbstractFunctionDecl:
217220
case Context::Inherited:
221+
case Context::CustomAttr:
218222
return false;
219223
}
220224
llvm_unreachable("unhandled kind");

test/NameLookup/custom_attrs_ambiguous.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,9 @@ import custom_attrs_B
99

1010
struct Test {
1111
@Wrapper var x: Int = 17
12-
// expected-error@-1 {{ambiguous use of attribute 'Wrapper'}}
13-
// expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Wrapper' in module 'custom_attrs_A'}} {{4-4=custom_attrs_A.}}
14-
// expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Wrapper' in module 'custom_attrs_B'}} {{4-4=custom_attrs_B.}}
12+
// expected-error@-1 {{'Wrapper' is ambiguous for type lookup in this context}}
1513

1614
init(@Builder closure: () -> Int) {}
17-
// expected-error@-1 {{ambiguous use of attribute 'Builder'}}
18-
// expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Builder' in module 'custom_attrs_A'}} {{9-9=custom_attrs_A.}}
19-
// expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Builder' in module 'custom_attrs_B'}} {{9-9=custom_attrs_B.}}
15+
// expected-error@-1 {{'Builder' is ambiguous for type lookup in this context}}
2016
}
2117

0 commit comments

Comments
 (0)