Files
swift-mirror/lib/Sema/ConstraintLocator.cpp
Doug Gregor bc158c31bf [Sema] Improve diagnostics for witness mismatches against @objc protocols.
Simplify and improve the checking of @objc names when matching a
witness to a requirement in the @objc protocol. First, don't use
@objc-ness as part of the initial screening to determine whether a
witness potentially matches an @objc requirement: we will only reject
a potential witness when the potential witness has an explicit
"@nonobjc" attribute on it. Otherwise, the presence of @objc and the
corresponding Objective-C name is checked only after selecting a
candidate. This more closely mirrors what we do for override checking,
where we match based on the Swift names (first) and validate
@objc'ness afterward. It is also a stepping stone to inferring
@objc'ness and @objc names from protocol conformances.

Second, when emitting a diagnostic about a missing or incorrect @objc
annotation, make sure the Fix-It gets the @objc name right: this might
mean adding the Objective-C name along with @objc (e.g.,
"@objc(fooWithString:bar:)"), adding the name to an
unadorned-but-explicit "@objc" attribute, or fixing the name of an
@objc attribute (e.g., "@objc(foo:bar:)" becomes
@objc(fooWithString:bar:)"). Make this diagnostic an error, rather
than a note on a generic "does not conform" diagnostic, so it's much
easier to see the diagnostic and apply the Fix-It.

Third, when emitting the warning about a non-@objc near-match for an
optional @objc requirement, provide two Fix-Its: one that adds the
appropriate @objc annotation (per the paragraph above), and one that
adds @nonobjc to silence the warning.

Part of the QoI improvements for conformances to @objc protocols,
rdar://problem/25159872.
2016-04-19 10:22:23 -07:00

241 lines
5.6 KiB
C++

//===--- ConstraintLocator.cpp - Constraint Locator -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the \c ConstraintLocator class and its related types,
// which is used by the constraint-based type checker to describe how
// a particular constraint was derived.
//
//===----------------------------------------------------------------------===//
#include "ConstraintLocator.h"
#include "ConstraintSystem.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
using namespace constraints;
void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
ArrayRef<PathElement> path) {
id.AddPointer(anchor);
id.AddInteger(path.size());
for (auto elt : path) {
id.AddInteger(elt.getKind());
switch (elt.getKind()) {
case Archetype:
id.AddPointer(elt.getArchetype()->getCanonicalType().getPointer());
break;
case Requirement:
id.AddPointer(elt.getRequirement());
break;
case Witness:
id.AddPointer(elt.getWitness());
break;
case AssociatedType:
id.AddPointer(elt.getAssociatedType());
break;
case ApplyArgument:
case ApplyFunction:
case FunctionArgument:
case FunctionResult:
case Member:
case MemberRefBase:
case UnresolvedMember:
case SubscriptIndex:
case SubscriptMember:
case SubscriptResult:
case ConstructorMember:
case RvalueAdjustment:
case ClosureResult:
case ParentType:
case InstanceType:
case SequenceIteratorProtocol:
case GeneratorElementType:
case ArrayElementType:
case ScalarToTuple:
case Load:
case GenericArgument:
case InterpolationArgument:
case NamedTupleElement:
case TupleElement:
case ApplyArgToParam:
case OpenedGeneric:
if (unsigned numValues = numNumericValuesInPathElement(elt.getKind())) {
id.AddInteger(elt.getValue());
if (numValues > 1)
id.AddInteger(elt.getValue2());
}
break;
}
}
}
void ConstraintLocator::dump(SourceManager *sm) {
dump(sm, llvm::errs());
llvm::errs() << "\n";
}
void ConstraintLocator::dump(ConstraintSystem *CS) {
dump(&CS->TC.Context.SourceMgr, llvm::errs());
llvm::errs() << "\n";
}
void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) {
out << "locator@" << (void*) this << " [";
if (anchor) {
out << Expr::getKindName(anchor->getKind());
if (sm) {
out << '@';
anchor->getLoc().print(out, *sm);
}
}
for (auto elt : getPath()) {
out << " -> ";
switch (elt.getKind()) {
case ArrayElementType:
out << "array element";
break;
case Archetype:
out << "archetype '" << elt.getArchetype()->getString() << "'";
break;
case AssociatedType:
out << "associated type '"
<< elt.getAssociatedType()->getNameStr() << "'";
break;
case ApplyArgument:
out << "apply argument";
break;
case ApplyFunction:
out << "apply function";
break;
case ApplyArgToParam:
out << "comparing call argument #" << llvm::utostr(elt.getValue())
<< " to parameter #" << llvm::utostr(elt.getValue2());
break;
case ClosureResult:
out << "closure result";
break;
case ConstructorMember:
out << "constructor member";
break;
case FunctionArgument:
out << "function argument";
break;
case FunctionResult:
out << "function result";
break;
case GeneratorElementType:
out << "generator element type";
break;
case GenericArgument:
out << "generic argument #" << llvm::utostr(elt.getValue());
break;
case InstanceType:
out << "instance type";
break;
case InterpolationArgument:
out << "interpolation argument #" << llvm::utostr(elt.getValue());
break;
case Load:
out << "load";
break;
case Member:
out << "member";
break;
case MemberRefBase:
out << "member reference base";
break;
case NamedTupleElement:
out << "named tuple element #" << llvm::utostr(elt.getValue());
break;
case UnresolvedMember:
out << "unresolved member";
break;
case ParentType:
out << "parent type";
break;
case RvalueAdjustment:
out << "rvalue adjustment";
break;
case ScalarToTuple:
out << "scalar to tuple";
break;
case SequenceIteratorProtocol:
out << "sequence iterator type";
break;
case SubscriptIndex:
out << "subscript index";
break;
case SubscriptMember:
out << "subscript member";
break;
case SubscriptResult:
out << "subscript result";
break;
case TupleElement:
out << "tuple element #" << llvm::utostr(elt.getValue());
break;
case Requirement:
out << "requirement ";
elt.getRequirement()->dumpRef(out);
break;
case Witness:
out << "witness ";
elt.getWitness()->dumpRef(out);
break;
case OpenedGeneric:
out << "opened generic";
break;
}
}
out << ']';
}