-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
TypeMatcher.cpp
145 lines (121 loc) · 7.25 KB
/
TypeMatcher.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (c) 2021-2024 ChilliBits. All rights reserved.
#include "TypeMatcher.h"
#include <symboltablebuilder/Scope.h>
namespace spice::compiler {
bool TypeMatcher::matchRequestedToCandidateTypes(const std::vector<SymbolType> &candidateTypes,
const std::vector<SymbolType> &reqTypes, TypeMapping &typeMapping,
ResolverFct &resolverFct, bool strictSpecifiers) {
// Check if the size of template types matches
if (reqTypes.size() != candidateTypes.size())
return false;
// Loop through both lists at the same time and match each pair of template types individually
for (size_t i = 0; i < candidateTypes.size(); i++) {
const SymbolType &reqType = reqTypes.at(i);
const SymbolType &candidateType = candidateTypes.at(i);
// Match the pair of template types
if (!matchRequestedToCandidateType(candidateType, reqType, typeMapping, resolverFct, strictSpecifiers))
return false;
}
return true;
}
bool TypeMatcher::matchRequestedToCandidateType(SymbolType candidateType, SymbolType requestedType, TypeMapping &typeMapping,
ResolverFct &resolverFct, bool strictSpecifierMatching,
bool isRequestedValueTemporary) {
// Unwrap as far as possible and remove reference wrappers if possible
SymbolType::unwrapBoth(candidateType, requestedType);
// If the candidate does not contain any generic parts, we can simply check for type equality
if (!candidateType.hasAnyGenericParts()) {
// Check if the right one is a struct that implements the interface on the left
if (candidateType.matchesInterfaceImplementedByStruct(requestedType))
return true;
// Normal equality check
return candidateType.matches(requestedType, true, !strictSpecifierMatching, true);
}
// Check if the candidate type itself is generic
if (candidateType.isBaseType(TY_GENERIC)) { // The candidate type itself is generic
const std::string genericTypeName = candidateType.getBaseType().getSubType();
// Check if we know the concrete type for that generic type name already
if (typeMapping.contains(genericTypeName)) { // This is a known generic type
SymbolType knownConcreteType = typeMapping.at(genericTypeName);
// Merge specifiers of candidate type and known concrete type together
knownConcreteType.specifiers = knownConcreteType.specifiers.merge(candidateType.specifiers);
// Remove reference wrapper of candidate type if required
if (!requestedType.isRef())
knownConcreteType = knownConcreteType.removeReferenceWrapper();
// Check if the known concrete type matches the requested type
return knownConcreteType.matches(requestedType, true, !strictSpecifierMatching, true);
} else { // This is an unknown generic type
// Retrieve generic candidate type by its name
const GenericType *genericCandidateType = resolverFct(genericTypeName);
assert(genericCandidateType != nullptr);
// Check if the requested type fulfills all conditions of the generic candidate type
if (!genericCandidateType->checkConditionsOf(requestedType, true, !strictSpecifierMatching))
return false;
// Zero out all specifiers in the requested type, that are present in the candidate type
// This is to set all specifiers that are not present in the candidate type to the generic type replacement
requestedType.specifiers.eraseWithMask(candidateType.specifiers);
// Add to type mapping
const SymbolType newMappingType = requestedType.hasAnyGenericParts() ? candidateType : requestedType;
assert(newMappingType.is(TY_GENERIC) || newMappingType.specifiers.isSigned != newMappingType.specifiers.isUnsigned);
typeMapping.insert({genericTypeName, newMappingType});
return true; // The type was successfully matched, by enriching the type mapping
}
} else { // The candidate type itself is non-generic, but one or several template or param types are
// Check if supertype and subtype are equal
if (requestedType.getSuperType() != candidateType.getSuperType())
return false;
// If we have a function/procedure type, check the param and return types. Otherwise, check the template types
if (candidateType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
// Check param and return types
const std::vector<SymbolType> &candidatePRTypes = candidateType.getFunctionParamAndReturnTypes();
const std::vector<SymbolType> &requestedPRTypes = requestedType.getFunctionParamAndReturnTypes();
if (!matchRequestedToCandidateTypes(candidatePRTypes, requestedPRTypes, typeMapping, resolverFct, strictSpecifierMatching))
return false;
} else {
if (requestedType.getSubType() != candidateType.getSubType())
return false;
if (requestedType.getBodyScope()->parent != candidateType.getBodyScope()->parent)
return false;
// Check template types
const std::vector<SymbolType> &candidateTTypes = candidateType.getTemplateTypes();
const std::vector<SymbolType> &requestedTTypes = requestedType.getTemplateTypes();
if (!matchRequestedToCandidateTypes(candidateTTypes, requestedTTypes, typeMapping, resolverFct, strictSpecifierMatching))
return false;
}
return true; // All requested template types match to their respective candidate template type -> successfully matched
}
}
void TypeMatcher::substantiateTypesWithTypeMapping(std::vector<SymbolType> &symbolTypes, const TypeMapping &typeMapping) {
for (SymbolType &symbolType : symbolTypes)
if (symbolType.hasAnyGenericParts())
substantiateTypeWithTypeMapping(symbolType, typeMapping);
}
void TypeMatcher::substantiateTypeWithTypeMapping(SymbolType &symbolType, const TypeMapping &typeMapping) {
assert(symbolType.hasAnyGenericParts());
// Check if the type itself is generic
if (symbolType.isBaseType(TY_GENERIC)) { // The symbol type itself is generic
const std::string genericTypeName = symbolType.getBaseType().getSubType();
assert(typeMapping.contains(genericTypeName));
const SymbolType &replacementType = typeMapping.at(genericTypeName);
symbolType = symbolType.replaceBaseType(replacementType);
} else { // The symbol type itself is non-generic, but one or several template or param types are
if (symbolType.getBaseType().isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
// Substantiate each param type
std::vector<SymbolType> paramTypes = symbolType.getFunctionParamAndReturnTypes();
for (SymbolType ¶mType : paramTypes)
if (paramType.hasAnyGenericParts())
substantiateTypeWithTypeMapping(paramType, typeMapping);
// Attach the list of concrete param types to the symbol type
symbolType.setFunctionParamAndReturnTypes(paramTypes);
} else {
// Substantiate each template type
std::vector<SymbolType> templateTypes = symbolType.getBaseType().getTemplateTypes();
for (SymbolType &templateType : templateTypes)
if (templateType.hasAnyGenericParts())
substantiateTypeWithTypeMapping(templateType, typeMapping);
// Attach the list of concrete template types to the symbol type
symbolType.setBaseTemplateTypes(templateTypes);
}
}
}
} // namespace spice::compiler