• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "typeRelationContext.h"
17 #include "boxingConverter.h"
18 #include "varbinder/scope.h"
19 #include "varbinder/variable.h"
20 #include "varbinder/declaration.h"
21 #include "checker/types/ets/etsUnionType.h"
22 #include "ir/expressions/arrayExpression.h"
23 #include "ir/ts/tsTypeParameter.h"
24 
25 namespace panda::es2panda::checker {
ValidateArrayTypeInitializerByElement(TypeRelation * relation,ir::ArrayExpression * node,ETSArrayType * target)26 void AssignmentContext::ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node,
27                                                               ETSArrayType *target)
28 {
29     if (target->IsETSTupleType()) {
30         return;
31     }
32 
33     for (uint32_t index = 0; index < node->Elements().size(); index++) {
34         ir::Expression *currentArrayElem = node->Elements()[index];
35         AssignmentContext(relation, currentArrayElem, currentArrayElem->Check(relation->GetChecker()->AsETSChecker()),
36                           target->ElementType(), currentArrayElem->Start(),
37                           {"Array element at index ", index, " is not compatible with the target array element type."});
38     }
39 }
40 
ValidateTypeArguments(ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs,const lexer::SourcePosition & pos)41 bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs,
42                                                  const lexer::SourcePosition &pos)
43 {
44     checker_->CheckNumberOfTypeArguments(type, typeArgs, pos);
45     if (type->TypeArguments().empty()) {
46         result_ = type;
47         return true;
48     }
49 
50     /*
51     The first loop is to create a substitution of typeParams & typeArgs.
52     so that we can replace the typeParams in constaints by the right type.
53     e.g:
54         class X <K extends Comparable<T>,T> {}
55         function main(){
56             const myCharClass = new X<Char,String>();
57         }
58     In the case above, the constraintsSubstitution should store "K->Char" and "T->String".
59     And in the second loop, we use this substitution to replace typeParams in constraints.
60     In this case, we will check "Comparable<String>" with "Char", since "Char" doesn't
61     extends "Comparable<String>", we will get an error here.
62     */
63 
64     auto const isDefaulted = [typeArgs](size_t idx) { return typeArgs == nullptr || idx >= typeArgs->Params().size(); };
65 
66     auto const getTypes = [this, &typeArgs, type, isDefaulted](size_t idx) -> std::pair<ETSTypeParameter *, Type *> {
67         auto *typeParam = type->TypeArguments().at(idx)->AsETSTypeParameter();
68         return {typeParam, isDefaulted(idx)
69                                ? typeParam->GetDefaultType()
70                                : checker_->MaybePromotedBuiltinType(typeArgs->Params().at(idx)->GetType(checker_))};
71     };
72 
73     auto *const substitution = checker_->NewSubstitution();
74 
75     for (size_t idx = 0; idx < type->TypeArguments().size(); ++idx) {
76         auto const [typeParam, typeArg] = getTypes(idx);
77         checker_->CheckValidGenericTypeParameter(typeArg, pos);
78         typeArg->Substitute(checker_->Relation(), substitution);
79         ETSChecker::EmplaceSubstituted(substitution, typeParam, typeArg);
80     }
81 
82     for (size_t idx = 0; idx < type->TypeArguments().size(); ++idx) {
83         auto const [typeParam, typeArg] = getTypes(idx);
84         if (typeParam->GetConstraintType() == nullptr) {
85             continue;
86         }
87         auto *const constraint = typeParam->GetConstraintType()->Substitute(checker_->Relation(), substitution);
88 
89         if (!ValidateTypeArg(constraint, typeArg) && typeArgs != nullptr &&
90             !checker_->Relation()->NoThrowGenericTypeAlias()) {
91             checker_->ThrowTypeError({"Type '", typeArg, "' is not assignable to constraint type '", constraint, "'."},
92                                      isDefaulted(idx) ? pos : typeArgs->Params().at(idx)->Start());
93         }
94     }
95 
96     return false;
97 }
98 
ValidateTypeArg(Type * constraintType,Type * typeArg)99 bool InstantiationContext::ValidateTypeArg(Type *constraintType, Type *typeArg)
100 {
101     // NOTE: #14993 enforce ETSChecker::IsReferenceType
102     if (typeArg->IsWildcardType()) {
103         return true;
104     }
105     return checker_->Relation()->IsAssignableTo(typeArg, constraintType);
106 }
107 
InstantiateType(ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs)108 void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs)
109 {
110     ArenaVector<Type *> typeArgTypes(checker_->Allocator()->Adapter());
111     typeArgTypes.reserve(type->TypeArguments().size());
112 
113     auto flags = ETSObjectFlags::NO_OPTS;
114 
115     if (typeArgs != nullptr) {
116         for (auto *const it : typeArgs->Params()) {
117             auto *paramType = checker_->GetTypeFromTypeAnnotation(it);
118 
119             if (paramType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
120                 checker_->Relation()->SetNode(it);
121                 auto *const boxedTypeArg = checker_->PrimitiveTypeAsETSBuiltinType(paramType);
122                 ASSERT(boxedTypeArg);
123                 paramType = boxedTypeArg->Instantiate(checker_->Allocator(), checker_->Relation(),
124                                                       checker_->GetGlobalTypesHolder());
125             }
126 
127             typeArgTypes.push_back(paramType);
128         }
129     }
130 
131     while (typeArgTypes.size() < type->TypeArguments().size()) {
132         typeArgTypes.push_back(type->TypeArguments().at(typeArgTypes.size()));
133     }
134 
135     InstantiateType(type, typeArgTypes, (typeArgs == nullptr) ? lexer::SourcePosition() : typeArgs->Range().start);
136     result_->AddObjectFlag(flags);
137 }
138 
InstantiateType(ETSObjectType * type,ArenaVector<Type * > & typeArgTypes,const lexer::SourcePosition & pos)139 void InstantiationContext::InstantiateType(ETSObjectType *type, ArenaVector<Type *> &typeArgTypes,
140                                            const lexer::SourcePosition &pos)
141 {
142     util::StringView hash = checker_->GetHashFromTypeArguments(typeArgTypes);
143     auto const &typeParams = type->TypeArguments();
144 
145     while (typeArgTypes.size() < typeParams.size()) {
146         typeArgTypes.push_back(typeParams.at(typeArgTypes.size()));
147     }
148 
149     auto *substitution = checker_->NewSubstitution();
150     auto *constraintsSubstitution = checker_->NewSubstitution();
151     for (size_t ix = 0; ix < typeParams.size(); ix++) {
152         if (!typeParams[ix]->IsETSTypeParameter()) {
153             continue;
154         }
155         ETSChecker::EmplaceSubstituted(constraintsSubstitution, typeParams[ix]->AsETSTypeParameter(), typeArgTypes[ix]);
156     }
157     for (size_t ix = 0; ix < typeParams.size(); ix++) {
158         auto *typeParam = typeParams[ix];
159         if (!typeParam->IsETSTypeParameter()) {
160             continue;
161         }
162         if (!checker_->IsCompatibleTypeArgument(typeParam->AsETSTypeParameter(), typeArgTypes[ix],
163                                                 constraintsSubstitution) &&
164             !checker_->Relation()->NoThrowGenericTypeAlias()) {
165             checker_->ThrowTypeError(
166                 {"Type ", typeArgTypes[ix], " is not assignable to", " type parameter ", typeParams[ix]}, pos);
167         }
168         ETSChecker::EmplaceSubstituted(substitution, typeParam->AsETSTypeParameter(), typeArgTypes[ix]);
169     }
170     result_ = type->Substitute(checker_->Relation(), substitution)->AsETSObjectType();
171 
172     type->GetInstantiationMap().try_emplace(hash, result_);
173     result_->AddTypeFlag(TypeFlag::GENERIC);
174 }
175 }  // namespace panda::es2panda::checker
176