Skip to content

Commit 70197c8

Browse files
authored
Merge pull request #41693 from hborla/any-in-diagnositcs
[Diagnostics] Print `any` in diagnostics.
2 parents ba149d9 + 80a2eee commit 70197c8

File tree

78 files changed

+649
-639
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+649
-639
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ ERROR(could_not_use_instance_member_on_type,none,
142142
"%select{| instance of nested}3 type %0",
143143
(Type, DeclNameRef, Type, bool))
144144
ERROR(could_not_use_member_on_existential,none,
145-
"member %1 cannot be used on value of protocol type %0; consider using a"
145+
"member %1 cannot be used on value of type %0; consider using a"
146146
" generic constraint instead",
147147
(Type, DeclNameRef))
148148
FIXIT(replace_with_type,"%0",(Type))
@@ -1945,9 +1945,8 @@ ERROR(type_cannot_conform_to_nsobject,none,
19451945
ERROR(use_of_equal_instead_of_equality,none,
19461946
"use of '=' in a boolean context, did you mean '=='?", ())
19471947
ERROR(type_cannot_conform, none,
1948-
"%select{type %1|protocol %1 as a type}0 cannot conform to "
1949-
"%select{%3|the protocol itself}2",
1950-
(bool, Type, bool, Type))
1948+
"type %0 cannot conform to %1",
1949+
(Type, Type))
19511950
NOTE(only_concrete_types_conform_to_protocols,none,
19521951
"only concrete types such as structs, enums and classes can conform to protocols",
19531952
())
@@ -2455,8 +2454,8 @@ ERROR(protocol_composition_one_class,none,
24552454
"contains class %1", (Type, Type))
24562455

24572456
ERROR(requires_conformance_nonprotocol,none,
2458-
"type %0 constrained to non-protocol, non-class type '%1'",
2459-
(Type, StringRef))
2457+
"type %0 constrained to non-protocol, non-class type %1",
2458+
(Type, Type))
24602459
NOTE(requires_conformance_nonprotocol_fixit,none,
24612460
"use '%0 == %1' to require '%0' to be '%1'",
24622461
(StringRef, StringRef))
@@ -2777,9 +2776,9 @@ WARNING(anyobject_class_inheritance_deprecated,Deprecation,
27772776
ERROR(multiple_inheritance,none,
27782777
"multiple inheritance from classes %0 and %1", (Type, Type))
27792778
ERROR(inheritance_from_non_protocol_or_class,none,
2780-
"inheritance from non-protocol, non-class type '%0'", (StringRef))
2779+
"inheritance from non-protocol, non-class type %0", (Type))
27812780
ERROR(inheritance_from_non_protocol,none,
2782-
"inheritance from non-protocol type '%0'", (StringRef))
2781+
"inheritance from non-protocol type %0", (Type))
27832782
ERROR(inheritance_from_anyobject,none,
27842783
"only protocols can inherit from 'AnyObject'", ())
27852784
ERROR(inheritance_from_parameterized_protocol,none,
@@ -3589,7 +3588,7 @@ ERROR(construct_protocol_value,none,
35893588
"value of type %0 is a protocol; it cannot be instantiated",
35903589
(Type))
35913590
ERROR(construct_protocol_by_name,none,
3592-
"protocol type %0 cannot be instantiated",
3591+
"type %0 cannot be instantiated",
35933592
(Type))
35943593

35953594
// Operators

include/swift/AST/PrintOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,13 @@ struct PrintOptions {
548548
return result;
549549
}
550550

551+
/// The print options used for formatting diagnostic arguments.
552+
static PrintOptions forDiagnosticArguments() {
553+
PrintOptions result;
554+
result.PrintExplicitAny = true;
555+
return result;
556+
}
557+
551558
/// Retrieve the set of options suitable for diagnostics printing.
552559
static PrintOptions printForDiagnostics(AccessLevel accessFilter,
553560
bool printFullConvention) {

include/swift/AST/Types.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5330,7 +5330,7 @@ class ExistentialType final : public TypeBase {
53305330
ConstraintType(constraintType) {}
53315331

53325332
public:
5333-
static Type get(Type constraint);
5333+
static Type get(Type constraint, bool forceExistential = false);
53345334

53355335
Type getConstraintType() const { return ConstraintType; }
53365336

@@ -6663,9 +6663,9 @@ inline bool TypeBase::hasSimpleTypeRepr() const {
66636663
return false;
66646664

66656665
case TypeKind::Metatype:
6666-
case TypeKind::ExistentialMetatype:
66676666
return !cast<const AnyMetatypeType>(this)->hasRepresentation();
66686667

6668+
case TypeKind::ExistentialMetatype:
66696669
case TypeKind::Existential:
66706670
return false;
66716671

lib/AST/ASTContext.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4260,15 +4260,17 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent,
42604260
RecursiveTypeProperties properties)
42614261
: NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { }
42624262

4263-
Type ExistentialType::get(Type constraint) {
4263+
Type ExistentialType::get(Type constraint, bool forceExistential) {
42644264
auto &C = constraint->getASTContext();
4265-
// FIXME: Any and AnyObject don't yet use ExistentialType.
4266-
if (constraint->isAny() || constraint->isAnyObject())
4267-
return constraint;
4265+
if (!forceExistential) {
4266+
// FIXME: Any and AnyObject don't yet use ExistentialType.
4267+
if (constraint->isAny() || constraint->isAnyObject())
4268+
return constraint;
42684269

4269-
// ExistentialMetatypeType is already an existential type.
4270-
if (constraint->is<ExistentialMetatypeType>())
4271-
return constraint;
4270+
// ExistentialMetatypeType is already an existential type.
4271+
if (constraint->is<ExistentialMetatypeType>())
4272+
return constraint;
4273+
}
42724274

42734275
assert(constraint->isConstraintType());
42744276

lib/AST/ASTPrinter.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5171,6 +5171,9 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
51715171
} else if (auto existential = dyn_cast<ExistentialType>(T.getPointer())) {
51725172
if (!Options.PrintExplicitAny)
51735173
return isSimpleUnderPrintOptions(existential->getConstraintType());
5174+
} else if (auto existential = dyn_cast<ExistentialMetatypeType>(T.getPointer())) {
5175+
if (!Options.PrintExplicitAny)
5176+
return isSimpleUnderPrintOptions(existential->getInstanceType());
51745177
}
51755178
return T->hasSimpleTypeRepr();
51765179
}
@@ -5591,10 +5594,32 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
55915594
}
55925595
}
55935596

5594-
if (T->is<ExistentialMetatypeType>() && Options.PrintExplicitAny)
5595-
Printer << "any ";
5597+
Type instanceType = T->getInstanceType();
5598+
if (Options.PrintExplicitAny) {
5599+
if (T->is<ExistentialMetatypeType>()) {
5600+
Printer << "any ";
5601+
5602+
// FIXME: We need to replace nested existential metatypes so that
5603+
// we don't print duplicate 'any'. This will be unnecessary once
5604+
// ExistentialMetatypeType is split into ExistentialType(MetatypeType).
5605+
instanceType = Type(instanceType).transform([](Type type) -> Type {
5606+
if (auto existential = type->getAs<ExistentialMetatypeType>())
5607+
return MetatypeType::get(existential->getInstanceType());
5608+
5609+
return type;
5610+
});
5611+
} else if (instanceType->isAny() || instanceType->isAnyObject()) {
5612+
// FIXME: 'any' is needed to distinguish between '(any Any).Type'
5613+
// and 'any Any.Type'. However, this combined with the above hack
5614+
// to replace nested existential metatypes with metatypes causes
5615+
// a bug in printing nested existential metatypes for Any and AnyObject,
5616+
// e.g. 'any (any Any).Type.Type'. This will be fixed by using
5617+
// ExistentialType for Any and AnyObject.
5618+
instanceType = ExistentialType::get(instanceType, /*forceExistential=*/true);
5619+
}
5620+
}
55965621

5597-
printWithParensIfNotSimple(T->getInstanceType());
5622+
printWithParensIfNotSimple(instanceType);
55985623

55995624
// We spell normal metatypes of existential types as .Protocol.
56005625
if (isa<MetatypeType>(T) &&
@@ -6294,7 +6319,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
62946319
if (printNamedOpaque())
62956320
return;
62966321

6297-
visit(T->getExistentialType());
6322+
auto constraint = T->getExistentialType();
6323+
if (auto existential = constraint->getAs<ExistentialType>())
6324+
constraint = existential->getConstraintType();
6325+
6326+
visit(constraint);
62986327
return;
62996328
}
63006329
case PrintOptions::OpaqueReturnTypePrintingMode::StableReference: {

lib/AST/DiagnosticEngine.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -670,10 +670,8 @@ static void formatDiagnosticArgument(StringRef Modifier,
670670
Type type;
671671
bool needsQualification = false;
672672

673-
// TODO: We should use PrintOptions::printForDiagnostic here, or we should
674-
// rename that method.
675-
PrintOptions printOptions{};
676-
673+
// Compute the appropriate print options for this argument.
674+
auto printOptions = PrintOptions::forDiagnosticArguments();
677675
if (Arg.getKind() == DiagnosticArgumentKind::Type) {
678676
type = Arg.getAsType()->getWithoutParens();
679677
if (type.isNull()) {

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6307,16 +6307,8 @@ GenericSignatureBuilder::finalize(TypeArrayView<GenericTypeParamType> genericPar
63076307
auto source = constraint.source;
63086308
auto loc = source->getLoc();
63096309

6310-
// FIXME: The constraint string is printed directly here because
6311-
// the current default is to not print `any` for existential
6312-
// types, but this error message is super confusing without `any`
6313-
// if the user wrote it explicitly.
6314-
PrintOptions options;
6315-
options.PrintExplicitAny = true;
6316-
auto constraintString = constraintType.getString(options);
6317-
63186310
Diags.diagnose(loc, diag::requires_conformance_nonprotocol,
6319-
subjectType, constraintString);
6311+
subjectType, constraintType);
63206312

63216313
auto getNameWithoutSelf = [&](std::string subjectTypeName) {
63226314
std::string selfSubstring = "Self.";
@@ -6331,10 +6323,12 @@ GenericSignatureBuilder::finalize(TypeArrayView<GenericTypeParamType> genericPar
63316323
if (allowConcreteGenericParams ||
63326324
(subjectType->is<DependentMemberType>() &&
63336325
!source->isProtocolRequirement())) {
6334-
auto subjectTypeName = subjectType.getString();
6326+
auto options = PrintOptions::forDiagnosticArguments();
6327+
auto subjectTypeName = subjectType.getString(options);
63356328
auto subjectTypeNameWithoutSelf = getNameWithoutSelf(subjectTypeName);
63366329
Diags.diagnose(loc, diag::requires_conformance_nonprotocol_fixit,
6337-
subjectTypeNameWithoutSelf, constraintString)
6330+
subjectTypeNameWithoutSelf,
6331+
constraintType.getString(options))
63386332
.fixItReplace(loc, " == ");
63396333
}
63406334
}

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -547,16 +547,8 @@ bool swift::rewriting::diagnoseRequirementErrors(
547547
if (subjectType->hasError() || constraint->hasError())
548548
break;
549549

550-
// FIXME: The constraint string is printed directly here because
551-
// the current default is to not print `any` for existential
552-
// types, but this error message is super confusing without `any`
553-
// if the user wrote it explicitly.
554-
PrintOptions options;
555-
options.PrintExplicitAny = true;
556-
auto constraintString = constraint.getString(options);
557-
558550
ctx.Diags.diagnose(loc, diag::requires_conformance_nonprotocol,
559-
subjectType, constraintString);
551+
subjectType, constraint);
560552
diagnosedError = true;
561553

562554
auto getNameWithoutSelf = [&](std::string subjectTypeName) {
@@ -570,10 +562,12 @@ bool swift::rewriting::diagnoseRequirementErrors(
570562
};
571563

572564
if (allowConcreteGenericParams) {
573-
auto subjectTypeName = subjectType.getString();
565+
auto options = PrintOptions::forDiagnosticArguments();
566+
auto subjectTypeName = subjectType.getString(options);
574567
auto subjectTypeNameWithoutSelf = getNameWithoutSelf(subjectTypeName);
575568
ctx.Diags.diagnose(loc, diag::requires_conformance_nonprotocol_fixit,
576-
subjectTypeNameWithoutSelf, constraintString)
569+
subjectTypeNameWithoutSelf,
570+
constraint.getString(options))
577571
.fixItReplace(loc, " == ");
578572
}
579573

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -568,10 +568,7 @@ bool MissingConformanceFailure::diagnoseTypeCannotConform(
568568
constraintType = existential->getConstraintType();
569569

570570
emitDiagnostic(diag::type_cannot_conform,
571-
nonConformingType->isExistentialType(),
572-
nonConformingType,
573-
constraintType->isEqual(protocolType),
574-
protocolType);
571+
nonConformingType, protocolType);
575572

576573
bool emittedSpecializedNote = false;
577574
if (auto protoType = protocolType->getAs<ProtocolType>()) {
@@ -2369,9 +2366,7 @@ bool ContextualFailure::diagnoseAsError() {
23692366
if (auto existential = constraintType->getAs<ExistentialType>())
23702367
constraintType = existential->getConstraintType();
23712368

2372-
emitDiagnostic(diag::type_cannot_conform,
2373-
/*isExistentialType=*/true, fromType,
2374-
constraintType->isEqual(toType), toType);
2369+
emitDiagnostic(diag::type_cannot_conform, fromType, toType);
23752370
emitDiagnostic(diag::only_concrete_types_conform_to_protocols);
23762371
return true;
23772372
}
@@ -3123,7 +3118,7 @@ bool ContextualFailure::tryProtocolConformanceFixIt(
31233118
// Emit a diagnostic to inform the user that they need to conform to the
31243119
// missing protocols.
31253120
auto conformanceDiag =
3126-
emitDiagnostic(diag::assign_protocol_conformance_fix_it, unwrappedToType,
3121+
emitDiagnostic(diag::assign_protocol_conformance_fix_it, constraint,
31273122
nominal->getDescriptiveKind(), fromType);
31283123
if (nominal->getInherited().size() > 0) {
31293124
auto lastInherited = nominal->getInherited().back().getLoc();
@@ -3231,7 +3226,7 @@ bool ContextualFailure::isIntegerToStringIndexConversion() const {
32313226
Optional<Diag<Type, Type>>
32323227
ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
32333228
Type contextualType) {
3234-
auto forProtocol = contextualType->isExistentialType();
3229+
auto forProtocol = contextualType->isConstraintType();
32353230
switch (context) {
32363231
case CTP_Initialization: {
32373232
if (contextualType->isAnyObject())

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -335,19 +335,11 @@ static void checkInheritanceClause(
335335
}
336336
}
337337

338-
// FIXME: The inherited type is printed directly here because
339-
// the current default is to not print `any` for existential
340-
// types, but this error message is super confusing without `any`
341-
// if the user wrote it explicitly.
342-
PrintOptions options;
343-
options.PrintExplicitAny = true;
344-
auto inheritedTyString = inheritedTy.getString(options);
345-
346338
// We can't inherit from a non-class, non-protocol type.
347339
decl->diagnose(canHaveSuperclass
348340
? diag::inheritance_from_non_protocol_or_class
349341
: diag::inheritance_from_non_protocol,
350-
inheritedTyString);
342+
inheritedTy);
351343
// FIXME: Note pointing to the declaration 'inheritedTy' references?
352344
}
353345
}

0 commit comments

Comments
 (0)