Skip to content

Commit afec252

Browse files
committed
[ConstraintSystem] Extract PotentialBinding and its auxiliary classes into a separate header
Create a new namespace - `swift::constraints::inference` and associate `PotentialBinding` with it. This way it would be possible for constraint graph to operate on `PotentialBinding(s)` in the future.
1 parent 10160cb commit afec252

File tree

5 files changed

+236
-183
lines changed

5 files changed

+236
-183
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
//===--- ConstraintGraph.h - Constraint Graph -------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the \c PotentialBindings class and its auxilary types
14+
// such as \c PotentialBinding, that are used to descibe bindings which
15+
// a particular type variable could be bound to.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
#ifndef SWIFT_SEMA_CSBINDINGS_H
19+
#define SWIFT_SEMA_CSBINDINGS_H
20+
21+
#include "swift/AST/Type.h"
22+
#include "swift/AST/Types.h"
23+
#include "swift/Sema/Constraint.h"
24+
#include "llvm/ADT/PointerUnion.h"
25+
26+
namespace swift {
27+
28+
class ProtocolDecl;
29+
30+
namespace constraints {
31+
32+
class ConstraintLocator;
33+
34+
namespace inference {
35+
36+
/// The kind of bindings that are permitted.
37+
enum class AllowedBindingKind : uint8_t {
38+
/// Only the exact type.
39+
Exact,
40+
/// Supertypes of the specified type.
41+
Supertypes,
42+
/// Subtypes of the specified type.
43+
Subtypes
44+
};
45+
46+
/// The kind of literal binding found.
47+
enum class LiteralBindingKind : uint8_t {
48+
None,
49+
Collection,
50+
Float,
51+
Atom,
52+
};
53+
54+
/// A potential binding from the type variable to a particular type,
55+
/// along with information that can be used to construct related
56+
/// bindings, e.g., the supertypes of a given type.
57+
struct PotentialBinding {
58+
/// The type to which the type variable can be bound.
59+
Type BindingType;
60+
61+
/// The kind of bindings permitted.
62+
AllowedBindingKind Kind;
63+
64+
protected:
65+
/// The source of the type information.
66+
///
67+
/// Determines whether this binding represents a "hole" in
68+
/// constraint system. Such bindings have no originating constraint
69+
/// because they are synthetic, they have a locator instead.
70+
PointerUnion<Constraint *, ConstraintLocator *> BindingSource;
71+
72+
PotentialBinding(Type type, AllowedBindingKind kind,
73+
PointerUnion<Constraint *, ConstraintLocator *> source)
74+
: BindingType(type), Kind(kind), BindingSource(source) {}
75+
76+
public:
77+
PotentialBinding(Type type, AllowedBindingKind kind, Constraint *source)
78+
: PotentialBinding(
79+
type->getWithoutParens(), kind,
80+
PointerUnion<Constraint *, ConstraintLocator *>(source)) {}
81+
82+
bool isDefaultableBinding() const {
83+
if (auto *constraint = BindingSource.dyn_cast<Constraint *>())
84+
return constraint->getKind() == ConstraintKind::Defaultable;
85+
// If binding source is not constraint - it's a hole, which is
86+
// a last resort default binding for a type variable.
87+
return true;
88+
}
89+
90+
bool hasDefaultedLiteralProtocol() const {
91+
return bool(getDefaultedLiteralProtocol());
92+
}
93+
94+
ProtocolDecl *getDefaultedLiteralProtocol() const {
95+
auto *constraint = BindingSource.dyn_cast<Constraint *>();
96+
if (!constraint)
97+
return nullptr;
98+
99+
return constraint->getKind() == ConstraintKind::LiteralConformsTo
100+
? constraint->getProtocol()
101+
: nullptr;
102+
}
103+
104+
ConstraintLocator *getLocator() const {
105+
if (auto *constraint = BindingSource.dyn_cast<Constraint *>())
106+
return constraint->getLocator();
107+
return BindingSource.get<ConstraintLocator *>();
108+
}
109+
110+
Constraint *getSource() const { return BindingSource.get<Constraint *>(); }
111+
112+
PotentialBinding withType(Type type) const {
113+
return {type, Kind, BindingSource};
114+
}
115+
116+
PotentialBinding withSameSource(Type type, AllowedBindingKind kind) const {
117+
return {type, kind, BindingSource};
118+
}
119+
120+
/// Determine whether this binding could be a viable candidate
121+
/// to be "joined" with some other binding. It has to be at least
122+
/// a non-default r-value supertype binding with no type variables.
123+
bool isViableForJoin() const;
124+
125+
static PotentialBinding forHole(TypeVariableType *typeVar,
126+
ConstraintLocator *locator) {
127+
return {HoleType::get(typeVar->getASTContext(), typeVar),
128+
AllowedBindingKind::Exact,
129+
/*source=*/locator};
130+
}
131+
132+
static PotentialBinding forPlaceholder(Type placeholderTy) {
133+
return {placeholderTy, AllowedBindingKind::Exact,
134+
PointerUnion<Constraint *, ConstraintLocator *>()};
135+
}
136+
};
137+
138+
} // end namespace inference
139+
140+
} // end namespace constraints
141+
142+
} // end namespace swift
143+
144+
namespace llvm {
145+
146+
template <>
147+
struct DenseMapInfo<swift::constraints::inference::PotentialBinding> {
148+
using Binding = swift::constraints::inference::PotentialBinding;
149+
150+
static Binding getEmptyKey() {
151+
return placeholderKey(llvm::DenseMapInfo<swift::TypeBase *>::getEmptyKey());
152+
}
153+
154+
static Binding getTombstoneKey() {
155+
return placeholderKey(
156+
llvm::DenseMapInfo<swift::TypeBase *>::getTombstoneKey());
157+
}
158+
159+
static unsigned getHashValue(const Binding &Val) {
160+
return DenseMapInfo<swift::Type>::getHashValue(
161+
Val.BindingType->getCanonicalType());
162+
}
163+
164+
static bool isEqual(const Binding &LHS, const Binding &RHS) {
165+
auto lhsTy = LHS.BindingType.getPointer();
166+
auto rhsTy = RHS.BindingType.getPointer();
167+
168+
// Fast path: pointer equality.
169+
if (DenseMapInfo<swift::TypeBase *>::isEqual(lhsTy, rhsTy))
170+
return true;
171+
172+
// If either side is empty or tombstone, let's use pointer equality.
173+
{
174+
auto emptyTy = llvm::DenseMapInfo<swift::TypeBase *>::getEmptyKey();
175+
auto tombstoneTy =
176+
llvm::DenseMapInfo<swift::TypeBase *>::getTombstoneKey();
177+
178+
if (lhsTy == emptyTy || lhsTy == tombstoneTy)
179+
return lhsTy == rhsTy;
180+
181+
if (rhsTy == emptyTy || rhsTy == tombstoneTy)
182+
return lhsTy == rhsTy;
183+
}
184+
185+
// Otherwise let's drop the sugar and check.
186+
return LHS.BindingType->isEqual(RHS.BindingType);
187+
}
188+
189+
private:
190+
static Binding placeholderKey(swift::Type type) {
191+
return Binding::forPlaceholder(type);
192+
}
193+
};
194+
195+
} // end namespace llvm
196+
197+
#endif // SWIFT_SEMA_CSBINDINGS_H

0 commit comments

Comments
 (0)