* @file
*
* This file defines functions for collecting type constraints recursively. This process
* is called assumption.
*/
#include "TypeCheckerImpl.h"
#include "cangjie/AST/Match.h"
#include "cangjie/AST/Node.h"
using namespace Cangjie;
using namespace AST;
namespace {
void AddConstraint(TyVarEnv& typeConstraintCollection, Ty& subTy, Ty& upperBoundTy)
{
if (!subTy.IsGeneric()) {
return;
}
auto subGen = RawStaticCast<GenericsTy*>(&subTy);
subGen->upperBounds.insert(&upperBoundTy);
auto found = typeConstraintCollection.find(subGen);
if (found == typeConstraintCollection.end()) {
typeConstraintCollection.emplace(subGen, std::set<Ptr<Ty>>{&upperBoundTy});
} else {
found->second.insert(&upperBoundTy);
}
}
bool LookUpConstraintCollection(Ty& subTy, Ty& baseTy, const TyVarEnv& typeConstraintCollection)
{
if (&subTy == &baseTy) {
return true;
}
if (!subTy.IsGeneric()) {
return false;
}
auto found = typeConstraintCollection.find(StaticCast<TyVar*>(&subTy));
if (found == typeConstraintCollection.end()) {
return false;
}
return found->second.find(&baseTy) != found->second.end();
}
* Checking Whether the Upper Bound of Generics Has InvalidTy.
*/
bool IsUpperBoundsValid(const std::vector<OwnedPtr<Type>>& upperBounds)
{
for (auto& upper : upperBounds) {
if (!Ty::IsTyCorrect(upper->GetTy())) {
return false;
}
}
return true;
}
}
void TypeChecker::TypeCheckerImpl::PerformAssumeReferenceTypeUpperBound(TyVarUB& typeConstraintCollection,
GCBlames& blames, const AST::Type& referenceTypeUpperBound, const TypeSubst& typeMapping)
{
auto upperBoundTy = referenceTypeUpperBound.GetTy();
Ptr<Decl> baseDecl = Ty::GetDeclPtrOfTy(upperBoundTy);
if (baseDecl != nullptr && Ty::IsTyCorrect(upperBoundTy) && upperBoundTy->HasGeneric()) {
TypeSubst substituteMap = typeManager.GetSubstituteMapping(*upperBoundTy, typeMapping);
Assumption(typeConstraintCollection, blames, *baseDecl, substituteMap);
}
}
void TypeChecker::TypeCheckerImpl::AssumeOneUpperBound(
TyVarUB& typeConstraintCollection, GCBlames& blames, const AST::Type& upperBound, const TypeSubst& typeMapping)
{
switch (upperBound.astKind) {
case ASTKind::REF_TYPE:
case ASTKind::QUALIFIED_TYPE: {
PerformAssumeReferenceTypeUpperBound(typeConstraintCollection, blames, upperBound, typeMapping);
break;
}
default:
break;
}
}
void TypeChecker::TypeCheckerImpl::PerformAssumptionForOneGenericConstraint(
TyVarUB& typeConstraintCollection, GCBlames& blames, const GenericConstraint& gc, const TypeSubst& typeMapping)
{
auto subTypeTy = gc.type->GetTy();
if (!Ty::IsTyCorrect(subTypeTy)) {
return;
}
auto subTy = typeManager.GetInstantiatedTy(subTypeTy, typeMapping);
for (const auto& upperBound : gc.upperBounds) {
if (!upperBound) {
continue;
}
auto upperBoundTy = upperBound->GetTy();
if (!Ty::IsTyCorrect(upperBoundTy)) {
continue;
}
auto baseTy = typeManager.GetInstantiatedTy(upperBoundTy, typeMapping);
if (!subTy->IsGeneric() || LookUpConstraintCollection(*subTy, *baseTy, typeConstraintCollection)) {
continue;
}
AddConstraint(typeConstraintCollection, *subTy, *baseTy);
blames[subTy][baseTy].emplace(&gc);
AssumeOneUpperBound(typeConstraintCollection, blames, *upperBound, typeMapping);
}
}
void TypeChecker::TypeCheckerImpl::Assumption(
TyVarUB& typeConstraintCollection, GCBlames& blames, const AST::Decl& decl, const TypeSubst& typeMapping)
{
Ptr<Generic> generic = decl.GetGeneric();
if (generic == nullptr) {
return;
}
for (auto& gc : generic->genericConstraints) {
bool shouldCheckUpperBounds = gc && gc->type && !gc->upperBounds.empty() && IsUpperBoundsValid(gc->upperBounds);
if (shouldCheckUpperBounds) {
PerformAssumptionForOneGenericConstraint(typeConstraintCollection, blames, *gc, typeMapping);
}
}
}