private void CheckArgumentTypeCompatibility(DataType type, ArgumentSyntax arg) { var fromType = arg.Value.Type; if (!IsAssignableFrom(type, fromType)) { diagnostics.Add(TypeError.CannotConvert(file, arg.Value, fromType, type)); } }
public DataType CheckExpressionType( ExpressionSyntax expression, DataType expectedType) { var actualType = InferExpressionType(expression); // TODO check for type compatibility not equality if (!expectedType.Equals(actualType)) { diagnostics.Add(TypeError.CannotConvert(file, expression, actualType, expectedType)); } return(actualType); }
private void ResolveTypesInVariableDeclaration( VariableDeclarationStatementSyntax variableDeclaration) { InferExpressionType(variableDeclaration.Initializer); DataType type; if (variableDeclaration.TypeExpression != null) { type = CheckAndEvaluateTypeExpression(variableDeclaration.TypeExpression); } else if (variableDeclaration.Initializer != null) { type = variableDeclaration.Initializer.Type; // Use the initializer type unless it is constant switch (type) { case IntegerConstantType integerConstant: var value = integerConstant.Value; var byteCount = value.GetByteCount(); type = byteCount <= 4 ? DataType.Int : DataType.Int64; break; case StringConstantType stringConstant: throw new NotImplementedException(); } } else { diagnostics.Add(TypeError.NotImplemented(file, variableDeclaration.NameSpan, "Inference of local variable types not implemented")); type = DataType.Unknown; } variableDeclaration.Type = type; if (variableDeclaration.Initializer != null) { InsertImplicitConversionIfNeeded(ref variableDeclaration.Initializer, type); var initializerType = variableDeclaration.Initializer.Type; if (!IsAssignableFrom(type, initializerType)) { diagnostics.Add(TypeError.CannotConvert(file, variableDeclaration.Initializer, initializerType, type)); } } }
private DataType InferExpressionType(ExpressionSyntax expression) { if (expression == null) { return(DataType.Unknown); } switch (expression) { case ReturnExpressionSyntax returnExpression: if (returnExpression.ReturnValue != null) { InferExpressionType(returnExpression.ReturnValue); if (returnType != null) // TODO report an error { InsertImplicitConversionIfNeeded(ref returnExpression.ReturnValue, returnType); var type = returnExpression.ReturnValue.Type; if (!IsAssignableFrom(returnType, type)) { diagnostics.Add(TypeError.CannotConvert(file, returnExpression.ReturnValue, type, returnType)); } } } else { // TODO a void or never function shouldn't have this } return(expression.Type = DataType.Never); case IntegerLiteralExpressionSyntax integerLiteral: return(expression.Type = new IntegerConstantType(integerLiteral.Value)); case StringLiteralExpressionSyntax _: return(expression.Type = DataType.StringConstant); case BoolLiteralExpressionSyntax _: return(expression.Type = DataType.Bool); case BinaryExpressionSyntax binaryOperatorExpression: return(InferBinaryExpressionType(binaryOperatorExpression)); case IdentifierNameSyntax identifierName: { var symbols = identifierName.LookupInContainingScope(); DataType type; switch (symbols.Count) { case 0: diagnostics.Add(NameBindingError.CouldNotBindName(file, identifierName.Span)); identifierName.ReferencedSymbol = UnknownSymbol.Instance; type = DataType.Unknown; break; case 1: identifierName.ReferencedSymbol = symbols.Single(); type = symbols.Single().Type; break; default: diagnostics.Add(NameBindingError.AmbiguousName(file, identifierName.Span)); identifierName.ReferencedSymbol = UnknownSymbol.Instance; type = DataType.Unknown; break; } return(identifierName.Type = type); } case UnaryExpressionSyntax unaryOperatorExpression: return(InferUnaryExpressionType(unaryOperatorExpression)); case ReferenceLifetimeSyntax lifetimeType: InferExpressionType(lifetimeType.ReferentTypeExpression); if (!IsType(lifetimeType.ReferentTypeExpression.Type)) { diagnostics.Add(TypeError.MustBeATypeExpression(file, lifetimeType.ReferentTypeExpression.Span)); } return(expression.Type = DataType.Type); case BlockSyntax blockExpression: foreach (var statement in blockExpression.Statements) { ResolveTypesInStatement(statement); } return(expression.Type = DataType.Void); // TODO assign the correct type to the block case NewObjectExpressionSyntax newObjectExpression: return(InferConstructorCallType(newObjectExpression)); case PlacementInitExpressionSyntax placementInitExpression: foreach (var argument in placementInitExpression.Arguments) { InferArgumentType(argument); } // TODO verify argument types against called function return(placementInitExpression.Type = CheckAndEvaluateTypeExpression(placementInitExpression.Initializer)); case ForeachExpressionSyntax foreachExpression: foreachExpression.Type = CheckAndEvaluateTypeExpression(foreachExpression.TypeExpression); InferExpressionType(foreachExpression.InExpression); // TODO check the break types InferExpressionType(foreachExpression.Block); // TODO assign correct type to the expression return(expression.Type = DataType.Void); case WhileExpressionSyntax whileExpression: CheckExpressionType(whileExpression.Condition, DataType.Bool); InferExpressionType(whileExpression.Block); // TODO assign correct type to the expression return(expression.Type = DataType.Void); case LoopExpressionSyntax loopExpression: InferExpressionType(loopExpression.Block); // TODO assign correct type to the expression return(expression.Type = DataType.Void); case InvocationSyntax invocation: return(InferInvocationType(invocation)); case GenericNameSyntax genericName: { foreach (var argument in genericName.Arguments) { InferExpressionType(argument.Value); } genericName.NameType.BeginFulfilling(); var nameType = InferNameType(genericName); // TODO check that argument types match function type genericName.NameType.Fulfill(nameType); switch (nameType) { case MetaFunctionType metaFunctionType: return(genericName.Type = metaFunctionType.ResultType); case UnknownType _: return(genericName.Type = DataType.Unknown); default: throw NonExhaustiveMatchException.For(genericName.NameType); } } case RefTypeSyntax refType: CheckAndEvaluateTypeExpression(refType.ReferencedType); return(refType.Type = DataType.Type); case UnsafeExpressionSyntax unsafeExpression: InferExpressionType(unsafeExpression.Expression); return(unsafeExpression.Type = unsafeExpression.Expression.Type); case MutableExpressionSyntax mutableExpression: { var expressionType = InferExpressionType(mutableExpression.Expression); DataType type; if (expressionType is Metatype) { type = DataType.Type; // It names/describes a type } else { // TODO check that the type actually is mutable so we can mutably borrow it type = expressionType; } return(mutableExpression.Type = type); } case IfExpressionSyntax ifExpression: CheckExpressionType(ifExpression.Condition, DataType.Bool); InferExpressionType(ifExpression.ThenBlock); InferExpressionType(ifExpression.ElseClause); // TODO assign a type to the expression return(ifExpression.Type = DataType.Void); case ResultExpressionSyntax resultExpression: InferExpressionType(resultExpression.Expression); return(resultExpression.Type = DataType.Never); case MemberAccessExpressionSyntax memberAccess: return(InferMemberAccessType(memberAccess)); case BreakExpressionSyntax breakExpression: InferExpressionType(breakExpression.Value); return(breakExpression.Type = DataType.Never); case AssignmentExpressionSyntax assignmentExpression: var left = InferExpressionType(assignmentExpression.LeftOperand); InferExpressionType(assignmentExpression.RightOperand); InsertImplicitConversionIfNeeded(ref assignmentExpression.RightOperand, left); var right = assignmentExpression.RightOperand.Type; if (!IsAssignableFrom(left, right)) { diagnostics.Add(TypeError.CannotConvert(file, assignmentExpression.RightOperand, right, left)); } return(assignmentExpression.Type = DataType.Void); case SelfExpressionSyntax _: return(selfType ?? DataType.Unknown); case MoveExpressionSyntax moveExpression: { var type = InferExpressionType(moveExpression.Expression); if (type is ReferenceType referenceType && !referenceType.IsOwned) { diagnostics.Add(TypeError.CannotMoveBorrowedValue(file, moveExpression)); type = referenceType.WithLifetime(Lifetime.Owned); } return(moveExpression.Type = type); } default: throw NonExhaustiveMatchException.For(expression); } }