//===--- Constraint.cpp - Constraint in the Type Checker --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 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 Constraint class and its related types, // which is used by the constraint-based type checker to describe a // constraint that must be solved. // //===----------------------------------------------------------------------===// #include "Constraint.h" #include "ConstraintSystem.h" #include "swift/AST/Types.h" #include "llvm/Support/raw_ostream.h" using namespace swift; using namespace constraints; Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Identifier Member, ConstraintLocator *locator) : Kind(Kind), Types { First, Second, Member }, Locator(locator) { switch (Kind) { case ConstraintKind::Bind: case ConstraintKind::Equal: case ConstraintKind::TrivialSubtype: case ConstraintKind::Subtype: case ConstraintKind::Conversion: case ConstraintKind::Construction: case ConstraintKind::ConformsTo: assert(Member.empty() && "Relational constraint cannot have a member"); break; case ConstraintKind::ApplicableFunction: assert(First->is() && "The left-hand side type should be a function type"); assert(Member.empty() && "Relational constraint cannot have a member"); break; case ConstraintKind::TypeMember: case ConstraintKind::ValueMember: assert(!Member.empty() && "Member constraint has no member"); break; case ConstraintKind::Archetype: case ConstraintKind::Class: case ConstraintKind::DynamicLookupValue: assert(Member.empty() && "Type property cannot have a member"); assert(Second.isNull() && "Type property with second type"); break; case ConstraintKind::Conjunction: llvm_unreachable("Conjunction constraints should use create()"); case ConstraintKind::Disjunction: llvm_unreachable("Disjunction constraints should use create()"); } } ProtocolDecl *Constraint::getProtocol() const { assert(Kind==ConstraintKind::ConformsTo && "Not a conformance constraint"); return Types.Second->castTo()->getDecl(); } void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { if (Kind == ConstraintKind::Conjunction || Kind == ConstraintKind::Disjunction) { bool isConjunction = (Kind == ConstraintKind::Conjunction); if (isConjunction) Out << "conjunction"; else Out << "disjunction"; if (Locator) { Out << " [["; Locator->dump(sm); Out << "]]"; } Out << ":"; bool first = true; for (auto constraint : getNestedConstraints()) { if (first) first = false; else if (isConjunction) Out << " and "; else Out << " or "; constraint->print(Out, sm); } return; } Types.First->print(Out); bool skipSecond = false; switch (Kind) { case ConstraintKind::Bind: Out << " := "; break; case ConstraintKind::Equal: Out << " == "; break; case ConstraintKind::TrivialSubtype: Out << " print(Out); if (Locator) { Out << " [["; Locator->dump(sm); Out << "]];"; } } void Constraint::dump(SourceManager *sm) const { print(llvm::errs(), sm); } Constraint *Constraint::createConjunction(ConstraintSystem &cs, ArrayRef constraints, ConstraintLocator *locator) { // Unwrap any conjunctions inside the conjunction constraint. bool unwrappedAny = false; SmallVector unwrapped; unsigned index = 0; for (auto constraint : constraints) { // If we have a nested conjunction, unwrap it. if (constraint->getKind() == ConstraintKind::Conjunction) { // If we haven't unwrapped anything before, copy all of the constraints // we skipped. if (!unwrappedAny) { unwrapped.append(constraints.begin(), constraints.begin() + index); unwrappedAny = true; } // Add all of the constraints in the conjunction. unwrapped.append(constraint->getNestedConstraints().begin(), constraint->getNestedConstraints().end()); } else if (unwrappedAny) { // Since we unwrapped constraints before, add this constraint. unwrapped.push_back(constraint); } // FIXME: If we find any disjunctions in here, should we distribute them? ++index; } // If we unwrapped anything, our list of constraints is the unwrapped list. if (unwrappedAny) constraints = unwrapped; assert(!constraints.empty() && "Empty conjunction constraint"); // If there is a single constraint, this isn't a disjunction at all. if (constraints.size() == 1) return constraints.front(); // Create the conjunction constraint. return new (cs) Constraint(ConstraintKind::Conjunction, cs.allocateCopy(constraints), locator); } Constraint *Constraint::createDisjunction(ConstraintSystem &cs, ArrayRef constraints, ConstraintLocator *locator) { // Unwrap any disjunctions inside the disjunction constraint; we only allow // disjunctions at the top level. bool unwrappedAny = false; SmallVector unwrapped; unsigned index = 0; for (auto constraint : constraints) { // If we have a nested disjunction, unwrap it. if (constraint->getKind() == ConstraintKind::Disjunction) { // If we haven't unwrapped anything before, copy all of the constraints // we skipped. if (!unwrappedAny) { unwrapped.append(constraints.begin(), constraints.begin() + index); unwrappedAny = true; } // Add all of the constraints in the disjunction. unwrapped.append(constraint->getNestedConstraints().begin(), constraint->getNestedConstraints().end()); } else if (unwrappedAny) { // Since we unwrapped constraints before, add this constraint. unwrapped.push_back(constraint); } ++index; } // If we unwrapped anything, our list of constraints is the unwrapped list. if (unwrappedAny) constraints = unwrapped; assert(!constraints.empty() && "Empty disjunction constraint"); // If there is a single constraint, this isn't a disjunction at all. if (constraints.size() == 1) return constraints.front(); // Create the disjunction constraint. return new (cs) Constraint(ConstraintKind::Disjunction, cs.allocateCopy(constraints), locator); } void *Constraint::operator new(size_t bytes, ConstraintSystem& cs, size_t alignment) { return ::operator new (bytes, cs, alignment); }