1 /**
2 Copyright: Copyright (c) 2017-2019 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module vox.fe.passes.type_check;
7 
8 import std.stdio;
9 import std.string : format;
10 import vox.all;
11 
12 void pass_type_check(ref CompilationContext context, CompilePassPerModule[] subPasses)
13 {
14 	auto state = TypeCheckState(&context);
15 
16 	foreach (ref SourceFileInfo file; context.files.data) {
17 		AstIndex modIndex = file.mod.get_ast_index(&context);
18 		require_type_check(modIndex, state);
19 		assert(context.analisysStack.length == 0);
20 
21 		if (context.printAstSema && modIndex) {
22 			writefln("// AST typed `%s`", file.name);
23 			print_ast(context.getAstNodeIndex(file.mod), &context, 2);
24 		}
25 	}
26 }
27 
28 // TODO: remove later, when no calls that pass IsNested.no remain.
29 enum IsNested : bool {
30 	no = false,
31 	yes = true,
32 }
33 
34 struct TypeCheckState
35 {
36 	CompilationContext* context;
37 	AstIndex parentType;
38 }
39 
40 /// Type checking for static context
41 void require_type_check(ref AstIndex nodeIndex, CompilationContext* context, IsNested isNested = IsNested.yes)
42 {
43 	auto state = TypeCheckState(context);
44 	require_type_check(nodeIndex, state, isNested);
45 }
46 
47 // Assumes IsNested.yes
48 void require_type_check(ref AstNodes items, ref TypeCheckState state, IsNested isNested = IsNested.yes)
49 {
50 	foreach(ref AstIndex item; items) require_type_check(item, state, isNested);
51 }
52 
53 /// Annotates all expression nodes with their type
54 /// Type checking, casting
55 /// isNested:
56 ///   If true, then type check must be performed. If check is already in progress then it is an error.
57 ///   Indirect check requests over expr_name_use, expr_member pass false.
58 void require_type_check(ref AstIndex nodeIndex, ref TypeCheckState state, IsNested isNested = IsNested.yes)
59 {
60 	AstNode* node = state.context.getAstNode(nodeIndex);
61 	//writefln("require_type_check %s %s %s", node.astType, node.state, isNested);
62 
63 	switch(node.state) with(AstNodeState)
64 	{
65 		case name_register_self, name_register_nested, name_resolve:
66 			state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.type_check));
67 			state.context.circular_dependency;
68 		case type_check:
69 			if (isNested == IsNested.no) {
70 				// this is allowed. We simply return.
71 				return;
72 			}
73 			state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.type_check));
74 			state.context.circular_dependency;
75 		case parse_done:
76 			auto name_state = NameRegisterState(state.context);
77 			require_name_register_self(0, nodeIndex, name_state);
78 			state.context.throwOnErrors;
79 			goto case;
80 		case name_register_self_done:
81 			auto name_state = NameRegisterState(state.context);
82 			require_name_register(nodeIndex, name_state);
83 			state.context.throwOnErrors;
84 			goto case;
85 		case name_register_nested_done:
86 			require_name_resolve(nodeIndex, state.context);
87 			state.context.throwOnErrors;
88 			break;
89 		case name_resolve_done: break; // all requirement are done
90 		case type_check_done, ir_gen_done: return; // already type checked
91 		default: state.context.internal_error(node.loc, "Node %s in %s state", node.astType, node.state);
92 	}
93 
94 	state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.type_check));
95 	scope(success) state.context.pop_analized_node;
96 
97 	if (node.hasAttributes) {
98 		type_check_attributes(node.attributeInfo, state);
99 	}
100 
101 	final switch(node.astType) with(AstType)
102 	{
103 		case error: state.context.internal_error(node.loc, "Visiting error node");
104 		case abstract_node: state.context.internal_error(node.loc, "Visiting abstract node");
105 
106 		case decl_alias: type_check_alias(cast(AliasDeclNode*)node, state); break;
107 		case decl_alias_array: assert(false);
108 		case decl_builtin: assert(false);
109 		case decl_builtin_attribute: type_check_builtin_attribute(cast(BuiltinAttribNode*)node, state); break;
110 		case decl_module: type_check_module(cast(ModuleDeclNode*)node, state); break;
111 		case decl_package: assert(false);
112 		case decl_import: assert(false);
113 		case decl_function: type_check_func(cast(FunctionDeclNode*)node, state); break;
114 		case decl_var: type_check_var(cast(VariableDeclNode*)node, state); break;
115 		case decl_struct: type_check_struct(cast(StructDeclNode*)node, state); break;
116 		case decl_enum: type_check_enum(cast(EnumDeclaration*)node, state); break;
117 		case decl_enum_member: type_check_enum_member(cast(EnumMemberDecl*)node, state); break;
118 		case decl_static_assert: type_check_static_assert(cast(StaticAssertDeclNode*)node, state); break;
119 		case decl_static_foreach: assert(false);
120 		case decl_static_if: assert(false);
121 		case decl_static_version: assert(false);
122 		case decl_template: assert(false);
123 		case decl_template_param: assert(false);
124 
125 		case stmt_block: type_check_block(cast(BlockStmtNode*)node, state); break;
126 		case stmt_if: type_check_if(cast(IfStmtNode*)node, state); break;
127 		case stmt_while: type_check_while(cast(WhileStmtNode*)node, state); break;
128 		case stmt_do_while: type_check_do(cast(DoWhileStmtNode*)node, state); break;
129 		case stmt_for: type_check_for(cast(ForStmtNode*)node, state); break;
130 		case stmt_switch: type_check_switch(cast(SwitchStmtNode*)node, state); break;
131 		case stmt_return: type_check_return(cast(ReturnStmtNode*)node, state); break;
132 		case stmt_break: assert(false);
133 		case stmt_continue: assert(false);
134 
135 		case expr_name_use: type_check_name_use(nodeIndex, cast(NameUseExprNode*)node, state); break;
136 		case expr_member: type_check_member(nodeIndex, cast(MemberExprNode*)node, state); break;
137 		case expr_bin_op: type_check_binary_op(cast(BinaryExprNode*)node, state); break;
138 		case expr_un_op: type_check_unary_op(cast(UnaryExprNode*)node, state); break;
139 		case expr_call: type_check_call(nodeIndex, cast(CallExprNode*)node, state); break;
140 		case expr_named_argument: type_check_named_argument(cast(NamedArgumenExprNode*)node, state); break;
141 		case expr_index: type_check_index(nodeIndex, cast(IndexExprNode*)node, state); break;
142 		case expr_slice: type_check_expr_slice(cast(SliceExprNode*)node, state); break;
143 		case expr_type_conv: type_check_type_conv(cast(TypeConvExprNode*)node, state); break;
144 
145 		case literal_int: type_check_literal_int(cast(IntLiteralExprNode*)node, state); break;
146 		case literal_float: type_check_literal_float(cast(FloatLiteralExprNode*)node, state); break;
147 		case literal_string: type_check_literal_string(cast(StringLiteralExprNode*)node, state); break;
148 		case literal_null: type_check_literal_null(cast(NullLiteralExprNode*)node, state); break;
149 		case literal_bool: type_check_literal_bool(cast(BoolLiteralExprNode*)node, state); break;
150 		case literal_array: type_check_literal_array(cast(ArrayLiteralExprNode*)node, state); break;
151 		case literal_special: assert(false);
152 
153 		case type_basic: assert(false);
154 		case type_func_sig: type_check_func_sig(cast(FunctionSignatureNode*)node, state); break;
155 		case type_ptr: type_check_ptr(cast(PtrTypeNode*)node, state); break;
156 		case type_static_array: type_check_static_array(cast(StaticArrayTypeNode*)node, state); break;
157 		case type_slice: type_check_slice(cast(SliceTypeNode*)node, state); break;
158 	}
159 }
160 
161 void require_type_check_expr(AstIndex targetType, ref AstIndex nodeIndex, CompilationContext* context)
162 {
163 	auto state = TypeCheckState(context);
164 	state.parentType = targetType;
165 	require_type_check(nodeIndex, state);
166 }
167 
168 void require_type_check_expr(AstIndex targetType, ref AstIndex nodeIndex, ref TypeCheckState state)
169 {
170 	auto temp = state.parentType;
171 	state.parentType = targetType;
172 	require_type_check(nodeIndex, state);
173 	state.parentType = temp;
174 }
175 
176 TypeConvResKind checkTypeConversion(AstIndex fromTypeIndex, AstIndex toTypeIndex, ref AstIndex expr, CompilationContext* c)
177 {
178 	if (same_type(fromTypeIndex, toTypeIndex, c)) return TypeConvResKind.no_i;
179 
180 	if (fromTypeIndex == CommonAstNodes.type_error || toTypeIndex == CommonAstNodes.type_error)
181 		return TypeConvResKind.no_i;
182 
183 	TypeNode* fromType = fromTypeIndex.get_type(c);
184 	TypeNode* toType = toTypeIndex.get_type(c);
185 
186 	//writefln("checkTypeConversion %s -> %s", printer(fromTypeIndex, c), printer(toTypeIndex, c));
187 	//writefln("checkTypeConversion %s -> %s", printer(c.getAstNodeIndex(fromType), c), printer(c.getAstNodeIndex(toType), c));
188 	//writefln("checkTypeConversion %s", fromType.astType);
189 
190 	switch (fromType.astType) with(AstType) {
191 		case type_basic: return type_conv_basic(fromType.as_basic, toTypeIndex, expr, c);
192 		case type_ptr: return type_conv_ptr(fromType.as_ptr, toTypeIndex, expr, c);
193 		case type_slice: return type_conv_slice(fromType.as_slice, toTypeIndex, expr, c);
194 		case type_static_array: return type_conv_static_array(fromType.as_static_array, toTypeIndex, expr, c);
195 		case decl_enum: return checkTypeConversion(fromType.as_enum.memberType, toTypeIndex, expr, c);
196 		case type_func_sig: return type_conv_func_sig(fromType.as_func_sig, toTypeIndex, expr, c);
197 		case decl_struct: return type_conv_struct(fromType.as_struct, toTypeIndex, expr, c);
198 		default:
199 			c.internal_error(expr.loc(c), "Unhandled type conversion %s, %s", cast(AstType)fromTypeIndex.astType(c), toType.astType);
200 	}
201 }
202 
203 struct CommonTypeResult {
204 	AstIndex commonType;
205 	TypeConvResKind kindA;
206 	TypeConvResKind kindB;
207 }
208 
209 // leftExpr, rightExpr can be null
210 CommonTypeResult calcCommonType(AstIndex indexA, AstIndex indexB, AstIndex leftExpr, AstIndex rightExpr, CompilationContext* c)
211 	out(res; res.commonType.isDefined)
212 {
213 	if (same_type(indexA, indexB, c)) return CommonTypeResult(indexA, TypeConvResKind.no_i, TypeConvResKind.no_i);
214 
215 	TypeNode* typeA = indexA.get_type(c);
216 	TypeNode* typeB = indexB.get_type(c);
217 
218 	if (typeB.astType == AstType.decl_enum) {
219 		indexB = typeB.as_enum.memberType;
220 		typeB = indexB.get_type(c);
221 	}
222 
223 	restart_enum:
224 
225 	switch (typeA.astType) with(AstType) {
226 		case type_basic: return common_type_basic(typeA.as_basic, indexB, leftExpr, rightExpr, c);
227 		case type_slice: return CommonTypeResult(CommonAstNodes.type_error);
228 		case type_ptr: return common_type_ptr(typeA.as_ptr, indexB, c);
229 		case decl_enum:
230 			indexA = typeA.as_enum.memberType;
231 			typeA = indexA.get_type(c);
232 			goto restart_enum;
233 		default:
234 			return CommonTypeResult(CommonAstNodes.type_error);
235 	}
236 }
237 
238 void autoconvToBool(ref AstIndex exprIndex, CompilationContext* context)
239 {
240 	ExpressionNode* expr = exprIndex.get_expr(context);
241 	if (expr.type.isErrorType) return;
242 	if (!autoconvTo(exprIndex, CommonAstNodes.type_bool, context))
243 		context.error(expr.loc, "Cannot implicitly convert `%s` to bool",
244 			expr.type.typeName(context));
245 }
246 
247 void insertCast(ref AstIndex exprIndex, AstIndex typeIndex, TypeConvResKind kind, CompilationContext* c)
248 {
249 	//writefln("cast %s", kind);
250 	final switch(kind) with(TypeConvResKind)
251 	{
252 		case fail: assert(false);
253 		case no_e, no_i: return;
254 		case ii_e, ii_i, if_e, if_i, ff_e, ff_i, fi_e, fi_i, string_literal_to_u8_ptr:
255 			exprIndex = c.appendAst!TypeConvExprNode(exprIndex.loc(c), typeIndex, exprIndex);
256 			exprIndex.setState(c, AstNodeState.type_check_done);
257 			exprIndex.get_node(c).subType = kind;
258 			return;
259 		case override_expr_type_e, override_expr_type_i:
260 			exprIndex.get_expr(c).type = typeIndex;
261 			return;
262 		case array_literal_to_slice:
263 			ExpressionNode* expr = exprIndex.get_expr(c);
264 			exprIndex = c.appendAst!UnaryExprNode(expr.loc, typeIndex, UnOp.staticArrayToSlice, exprIndex);
265 			return;
266 	}
267 }
268 
269 bool autoconvToCommonType(ref AstIndex leftIndex, ref AstIndex rightIndex, CompilationContext* c)
270 {
271 	AstIndex leftType = leftIndex.get_expr_type(c);
272 	AstIndex rightType = rightIndex.get_expr_type(c);
273 	CommonTypeResult res = calcCommonType(leftType, rightType, leftIndex, rightIndex, c);
274 	//writefln("autoconvToCommonType %s %s %s", printer(leftType, c), printer(rightType, c), res);
275 	if (res.commonType == CommonAstNodes.type_error) return false;
276 	insertCast(leftIndex, res.commonType, res.kindA, c);
277 	insertCast(rightIndex, res.commonType, res.kindB, c);
278 	return true;
279 }
280 
281 /// Returns true if conversion was successful. False otherwise
282 bool autoconvTo(ref AstIndex exprIndex, AstIndex typeIndex, CompilationContext* c)
283 {
284 	AstIndex exprType = exprIndex.get_expr_type(c);
285 	//writefln("autoconvTo %s -> %s", printer(exprType, c), printer(typeIndex, c));
286 	if (exprType == typeIndex) return true;
287 
288 	TypeConvResKind res = checkTypeConversion(exprType, typeIndex, exprIndex, c);
289 	//writefln("autoconvTo %s %s %s", printer(exprType, c), printer(typeIndex, c), res);
290 	if (res.canConvertImplicitly)
291 	{
292 		insertCast(exprIndex, typeIndex, res, c);
293 		return true;
294 	}
295 	return false;
296 }