mirror of
https://github.com/apple/swift.git
synced 2026-06-20 15:42:51 +02:00
278 lines
8.3 KiB
C++
278 lines
8.3 KiB
C++
//===--- Score.h - Online scoring of partial solutions ----------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef SWIFT_SEMA_SCORE_H
|
|
#define SWIFT_SEMA_SCORE_H
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace swift {
|
|
|
|
namespace constraints {
|
|
|
|
/// Describes an aspect of a solution that affects its overall score, i.e., a
|
|
/// user-defined conversions.
|
|
enum ScoreKind: unsigned int {
|
|
// These values are used as indices into a Score value.
|
|
|
|
/// A fix needs to be applied to the source.
|
|
SK_Fix,
|
|
/// A hole in the constraint system.
|
|
SK_Hole,
|
|
/// A reference to an @unavailable declaration.
|
|
SK_Unavailable,
|
|
/// A reference to a declaration from a module that has not been imported.
|
|
SK_MissingImport,
|
|
/// A reference to an async function in a synchronous context.
|
|
///
|
|
/// \note Any score kind after this is considered a conversion that doesn't
|
|
/// require fixing the source and will be ignored during code completion.
|
|
SK_AsyncInSyncMismatch,
|
|
/// Synchronous function in an asynchronous context or a conversion of
|
|
/// a synchronous function to an asynchronous one.
|
|
SK_SyncInAsync,
|
|
/// A use of the "forward" scan for trailing closures.
|
|
SK_ForwardTrailingClosure,
|
|
/// A use of a disfavored overload.
|
|
SK_DisfavoredOverload,
|
|
/// A member for an \c UnresolvedMemberExpr found via unwrapped optional base.
|
|
SK_UnresolvedMemberViaOptional,
|
|
/// An implicit force of an implicitly unwrapped optional value.
|
|
SK_ForceUnchecked,
|
|
/// An implicit conversion from a value of one type (lhs)
|
|
/// to another type (rhs) via implicit initialization of
|
|
/// `rhs` type with an argument of `lhs` value.
|
|
SK_ImplicitValueConversion,
|
|
/// A user-defined conversion.
|
|
SK_UserConversion,
|
|
/// A non-trivial function conversion.
|
|
SK_FunctionConversion,
|
|
/// A literal expression bound to a non-default literal type.
|
|
SK_NonDefaultLiteral,
|
|
/// An implicit upcast conversion between collection types.
|
|
SK_CollectionUpcastConversion,
|
|
/// A value-to-optional conversion.
|
|
SK_ValueToOptional,
|
|
/// A conversion to an empty existential type ('Any' or '{}').
|
|
SK_EmptyExistentialConversion,
|
|
/// A key path application subscript.
|
|
SK_KeyPathSubscript,
|
|
/// A pointer conversion where the destination type is a generic parameter.
|
|
/// This should eventually be removed in favor of outright banning pointer
|
|
/// conversions for generic parameters. As such we consider it more impactful
|
|
/// than \c SK_ValueToPointerConversion.
|
|
SK_GenericParamPointerConversion,
|
|
/// A conversion from a string, array, or inout to a pointer.
|
|
SK_ValueToPointerConversion,
|
|
/// A closure/function conversion to an autoclosure parameter.
|
|
SK_FunctionToAutoClosureConversion,
|
|
/// A type with a missing conformance(s) that has be synthesized
|
|
/// or diagnosed later, such types are allowed to appear in
|
|
/// a valid solution.
|
|
SK_MissingSynthesizableConformance,
|
|
/// An unapplied reference to a function. The purpose of this
|
|
/// score bit is to prune overload choices that are functions
|
|
/// when a solution has already been found using property.
|
|
///
|
|
/// \Note The solver only prefers variables over functions
|
|
/// to resolve ambiguities, so please be sure that any score
|
|
/// kind added after this is truly less impactful. Only other
|
|
/// ambiguity tie-breakers should go after this; anything else
|
|
/// should be added above.
|
|
SK_UnappliedFunction,
|
|
|
|
SK_LastScoreKind = SK_UnappliedFunction,
|
|
};
|
|
|
|
/// The number of score kinds.
|
|
const unsigned NumScoreKinds = SK_LastScoreKind + 1;
|
|
|
|
struct Score;
|
|
/// Display a score.
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const Score &score);
|
|
|
|
/// Describes the fixed score of a solution to the constraint system.
|
|
struct Score {
|
|
unsigned Data[NumScoreKinds] = {};
|
|
|
|
friend Score &operator+=(Score &x, const Score &y) {
|
|
for (unsigned i = 0; i != NumScoreKinds; ++i) {
|
|
x.Data[i] += y.Data[i];
|
|
}
|
|
return x;
|
|
}
|
|
|
|
friend Score operator+(const Score &x, const Score &y) {
|
|
Score result;
|
|
for (unsigned i = 0; i != NumScoreKinds; ++i) {
|
|
result.Data[i] = x.Data[i] + y.Data[i];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
friend Score operator-(const Score &x, const Score &y) {
|
|
Score result;
|
|
for (unsigned i = 0; i != NumScoreKinds; ++i) {
|
|
ASSERT(x.Data[i] >= y.Data[i]);
|
|
result.Data[i] = x.Data[i] - y.Data[i];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
friend Score &operator-=(Score &x, const Score &y) {
|
|
for (unsigned i = 0; i != NumScoreKinds; ++i) {
|
|
ASSERT(x.Data[i] >= y.Data[i]);
|
|
x.Data[i] -= y.Data[i];
|
|
}
|
|
return x;
|
|
}
|
|
|
|
friend bool operator==(const Score &x, const Score &y) {
|
|
for (unsigned i = 0; i != NumScoreKinds; ++i) {
|
|
if (x.Data[i] != y.Data[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
friend bool operator!=(const Score &x, const Score &y) {
|
|
return !(x == y);
|
|
}
|
|
|
|
friend bool operator<(const Score &x, const Score &y) {
|
|
for (unsigned i = 0; i != NumScoreKinds; ++i) {
|
|
if (x.Data[i] < y.Data[i])
|
|
return true;
|
|
|
|
if (x.Data[i] > y.Data[i])
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
friend bool operator<=(const Score &x, const Score &y) {
|
|
return !(y < x);
|
|
}
|
|
|
|
friend bool operator>(const Score &x, const Score &y) {
|
|
return y < x;
|
|
}
|
|
|
|
friend bool operator>=(const Score &x, const Score &y) {
|
|
return !(x < y);
|
|
}
|
|
|
|
/// Return ScoreKind descriptions for printing alongside non-zero ScoreKinds
|
|
/// in debug output.
|
|
static std::string getNameFor(ScoreKind kind) {
|
|
switch (kind) {
|
|
case SK_Hole:
|
|
return "hole";
|
|
|
|
case SK_Unavailable:
|
|
return "use of an unavailable declaration";
|
|
|
|
case SK_MissingImport:
|
|
return "use of a declaration that has not been imported";
|
|
|
|
case SK_AsyncInSyncMismatch:
|
|
return "async-in-synchronous mismatch";
|
|
|
|
case SK_SyncInAsync:
|
|
return "sync-in-asynchronous";
|
|
|
|
case SK_ForwardTrailingClosure:
|
|
return "forward scan when matching a trailing closure";
|
|
|
|
case SK_Fix:
|
|
return "applied fix";
|
|
|
|
case SK_DisfavoredOverload:
|
|
return "disfavored overload";
|
|
|
|
case SK_UnresolvedMemberViaOptional:
|
|
return "unwrapping optional at unresolved member base";
|
|
|
|
case SK_ForceUnchecked:
|
|
return "force of an implicitly unwrapped optional";
|
|
|
|
case SK_UserConversion:
|
|
return "user conversion";
|
|
|
|
case SK_FunctionConversion:
|
|
return "function conversion";
|
|
|
|
case SK_NonDefaultLiteral:
|
|
return "non-default literal";
|
|
|
|
case SK_CollectionUpcastConversion:
|
|
return "collection upcast conversion";
|
|
|
|
case SK_ValueToOptional:
|
|
return "value to optional promotion";
|
|
|
|
case SK_EmptyExistentialConversion:
|
|
return "empty-existential conversion";
|
|
|
|
case SK_KeyPathSubscript:
|
|
return "key path subscript";
|
|
|
|
case SK_GenericParamPointerConversion:
|
|
return "pointer conversion to generic parameter";
|
|
|
|
case SK_ValueToPointerConversion:
|
|
return "value-to-pointer conversion";
|
|
|
|
case SK_FunctionToAutoClosureConversion:
|
|
return "function to autoclosure parameter conversion";
|
|
|
|
case SK_ImplicitValueConversion:
|
|
return "value-to-value conversion";
|
|
|
|
case SK_UnappliedFunction:
|
|
return "use of overloaded unapplied function";
|
|
|
|
case SK_MissingSynthesizableConformance:
|
|
return "type with missing synthesizable conformance";
|
|
}
|
|
}
|
|
|
|
/// Print Score list a with brief description of any non-zero ScoreKinds.
|
|
void print(llvm::raw_ostream &out) const {
|
|
bool hasNonDefault = false;
|
|
for (unsigned int i = 0; i < NumScoreKinds; ++i) {
|
|
if (Data[i] != 0) {
|
|
out << " [";
|
|
out << getNameFor(ScoreKind(i));
|
|
out << "(s), weight: ";
|
|
out << std::to_string(NumScoreKinds - i);
|
|
out << ", impact: ";
|
|
out << std::to_string(Data[i]);
|
|
out << "]";
|
|
hasNonDefault = true;
|
|
}
|
|
}
|
|
if (!hasNonDefault) {
|
|
out << " <default ";
|
|
out << *this;
|
|
out << ">";
|
|
}
|
|
}
|
|
};
|
|
|
|
} // end namespace constraints
|
|
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_SEMA_SCORE_H
|