Mercurial > projects > dang
view sema/TypeCheck.d @ 191:e799db8d9cb0
Fixed a small bug. Passes two more tests now.
author | Anders Johnsen <skabet@gmail.com> |
---|---|
date | Fri, 25 Jul 2008 14:44:50 +0200 |
parents | 86a2ede00e9a |
children | 658178183018 |
line wrap: on
line source
module sema.TypeCheck; import sema.Visitor, sema.Symbol, sema.DType; import tango.io.Stdout, Integer = tango.text.convert.Integer; import basic.SourceLocation, basic.Message; class TypeCheck : Visitor!(void) { this(MessageHandler messages) { this.messages = messages; } override void visitBinaryExp(BinaryExp exp) { super.visitBinaryExp(exp); if(!(exp.left.type is exp.right.type)) { if (!exp.right.type.hasImplicitConversionTo(exp.left.type) && !exp.left.type.hasImplicitConversionTo(exp.right.type)) messages.report(InvalidImplicitCast, exp.loc) .arg(exp.right.type.toString) .arg(exp.left.type.toString); else { CastExp castExp; if(exp.left.type.isReal && exp.right.type.isReal) if(exp.left.type.byteSize > exp.right.type.byteSize) castExp = new CastExp( SLoc.Invalid, new Identifier(exp.left.type.name), exp.right); else castExp = new CastExp( SLoc.Invalid, new Identifier(exp.right.type.name), exp.left); else if(exp.left.type.isReal || exp.right.type.isReal) if(exp.left.type.isReal) castExp = new CastExp( SLoc.Invalid, new Identifier(exp.left.type.name), exp.right); else castExp = new CastExp( SLoc.Invalid, new Identifier(exp.right.type.name), exp.left); else if(exp.left.type.byteSize > exp.right.type.byteSize) castExp = new CastExp( SLoc.Invalid, new Identifier(exp.left.type.name), exp.right); else if(exp.left.type.byteSize > exp.right.type.byteSize) castExp = new CastExp( SLoc.Invalid, new Identifier(exp.right.type.name), exp.left); else castExp = new CastExp( SLoc.Invalid, new Identifier(exp.left.type.name), exp.right); if(castExp) { castExp.env = exp.env; if(castExp.exp == exp.right) exp.right = castExp; else exp.left = castExp; } } } if (exp.op >= BinaryExp.Operator.LeftShift && exp.op <= BinaryExp.Operator.UnsignedRightShift) {} // FIXME: When we have const-system we need to check for // right site being larger then the bitsize of the // left } override void visitDerefExp(DerefExp exp) { if (!exp.exp.type.isPointer) { messages.report(CanOnlyDerefPointers, [exp.exp.sourceRange][], [exp.loc]) .arg(exp.exp.type.toString); exp._type = DType.Int; } } override void visitCallExp(CallExp exp) { super.visitCallExp(exp); if (auto iden = cast(MemberReference)exp.exp) { Symbol[] internalVisitMemberRef(MemberReference m) { Symbol[] visitRef(MemberReference m, Identifier target, Symbol st) { auto child = m.child; auto res = st.findMembers(child.get); return res; } switch(m.target.expType) { case ExpType.Identifier: return visitRef(m, cast(Identifier)m.target, (cast(Identifier)m.target).getSymbol); case ExpType.MemberReference: Symbol[] s = internalVisitMemberRef(cast(MemberReference)m.target); if(s.length) return s; return visitRef(m, cast(Identifier)m.target, s[0]); } } Exp[] newArgs; DFunction function_type; if (iden.type.isFunction()) { Symbol[] methods = internalVisitMemberRef(iden); if (!methods.length) { messages.report(NoMethodByName, iden.loc); return; } Symbol sel = getBestMatch(exp.args, methods); exp.callSym = sel; if (sel) function_type = sel.type.asFunction(); else { messages.report(NoMachingMethod, exp.loc); foreach ( i, s ; methods ) { messages.report(CandidateNr, (cast(FuncDecl)s.decl).identifier.loc) .arg(Integer.toString(i+1)); } } } else if (iden.type.isCallable) function_type = iden.type.asCallable(); else assert(0, "Should not happen"); foreach (i, arg; exp.args) { auto argType = function_type.params[i]; auto expType = arg.type; if (argType.isSame(expType)) { if (!expType.hasImplicitConversionTo(argType)) messages.report(InvalidImplicitCast, exp.loc) .arg(expType.toString) .arg(argType.toString); auto castExp = new CastExp( SLoc.Invalid, new Identifier(argType.name), arg); castExp.env = iden.env; newArgs ~= castExp; } else newArgs ~= arg; } exp.args = newArgs; } else if (auto iden = cast(Identifier)exp.exp) { Exp[] newArgs; DFunction function_type; if (iden.type.isFunction()) { Symbol[] methods; foreach (decl ; iden.env.find(iden.get)) methods ~= decl.sym; if (!methods.length) { messages.report(NoMethodByName, iden.loc); return; } Symbol sel = getBestMatch(exp.args, methods); exp.callSym = sel; if (sel) function_type = sel.type.asFunction(); else { messages.report(NoMachingMethod, exp.loc); foreach ( i, s ; methods ) { messages.report(CandidateNr, (cast(FuncDecl)s.decl).identifier.loc) .arg(Integer.toString(i+1)); } } } else if (iden.type.isCallable) function_type = iden.type.asCallable(); else assert(0, "Should not happen"); foreach (i, arg; exp.args) { auto argType = function_type.params[i]; auto expType = arg.type; if (!argType.isSame(expType)) { if (!expType.hasImplicitConversionTo(argType)) messages.report(InvalidImplicitCast, exp.loc) .arg(expType.toString) .arg(argType.toString); auto castExp = new CastExp( SLoc.Invalid, new Identifier(argType.name), arg); castExp.env = iden.env; newArgs ~= castExp; } else newArgs ~= arg; } exp.args = newArgs; } else { Exp[] newArgs; foreach(i, arg; exp.args) { auto argType = exp.exp.type.asFunction.params[i]; auto expType = arg.type; if(!argType.isSame(expType)) { if(!expType.hasImplicitConversionTo(argType)) messages.report(InvalidImplicitCast, exp.loc) .arg(expType.toString) .arg(argType.toString); auto castExp = new CastExp( SLoc.Invalid, new Identifier(argType.name), arg); castExp.env = exp.exp.env; newArgs ~= castExp; } else newArgs ~= arg; } exp.args = newArgs; } } override void visitNewExp(NewExp exp) { super.visitNewExp(exp); Exp[] newArgs; Symbol[] methods = exp.newType.getSymbol.findFunctionMembers("this"); if (!methods.length) { messages.report(NoConstructor, exp.newType.loc); return; } Symbol sel = getBestMatch(exp.c_args, methods); if (sel) { foreach (i, arg; exp.c_args) { auto argType = sel.type.asFunction.params[i]; auto expType = arg.type; if (!argType.isSame(expType)) { if (!expType.hasImplicitConversionTo(argType)) messages.report(InvalidImplicitCast, exp.loc) .arg(expType.toString) .arg(argType.toString); auto castExp = new CastExp( SLoc.Invalid, new Identifier(argType.name), arg); castExp.env = exp.newType.env; newArgs ~= castExp; } else newArgs ~= arg; } exp.c_args = newArgs; exp.callSym = sel; } else { messages.report(NoMachingCon, exp.newType.loc); foreach ( i, s ; methods ) { messages.report(CandidateNr, (cast(FuncDecl)s.decl).identifier.loc) .arg(Integer.toString(i+1)); } } } override void visitAssignExp(AssignExp exp) { super.visitAssignExp(exp); auto identifierType = exp.identifier.type; auto expType = exp.exp.type; if(!identifierType.isSame(expType)) { if(!expType.hasImplicitConversionTo(identifierType)) messages.report(InvalidImplicitCast, [exp.identifier.sourceRange, exp.exp.sourceRange][], [exp.loc]) .arg(expType.toString) .arg(identifierType.toString); auto castExp = new CastExp( SLoc.Invalid, new Identifier(identifierType.name), exp.exp); castExp.env = exp.exp.env; exp.exp = castExp; } if (expType.isStaticArray) messages.report(CannotReassignSArray, [exp.identifier.sourceRange, exp.exp.sourceRange][], [exp.loc]); } override void visitReturnStmt(ReturnStmt stmt) { super.visitReturnStmt(stmt); if(stmt.exp) { auto returnType = stmt.env.parentFunction.type.asFunction.returnType; auto expType = stmt.exp.type; if(!returnType.isSame(expType)) { if(!expType.hasImplicitConversionTo(returnType)) messages.report(InvalidImplicitCast, stmt.exp.loc) .arg(expType.toString) .arg(returnType.toString); auto castExp = new CastExp( SLoc.Invalid, new Identifier(returnType.name), stmt.exp); castExp.env = stmt.exp.env; stmt.exp = castExp; } } } override void visitVarDecl(VarDecl decl) { super.visitVarDecl(decl); if(decl.init) { auto varType = decl.identifier.type; auto expType = decl.init.type; if(!varType.isSame(expType)) { if(!expType.hasImplicitConversionTo(varType)) messages.report(InvalidImplicitCast, decl.init.loc) .arg(expType.toString) .arg(varType.toString); auto castExp = new CastExp( SLoc.Invalid, new Identifier(varType.name), decl.init); castExp.env = decl.init.env; decl.init = castExp; } } } private Symbol getBestMatch(Exp[] arg_list , Symbol[] available) in { foreach (a ; available) assert(a.type.isFunction, "A non-function found in available-list."); } body { assert(available.length, "No available methods in symbol-list."); Symbol[] possible; Symbol perfect; foreach (s ; available) { if (s.type.asFunction.params.length < arg_list.length) continue; bool per = true; bool work = true; foreach (i, arg; arg_list) { auto argType = s.type.asFunction.params[i]; auto expType = arg.type; if (argType.isSame(expType)) { per = false; if( !expType.hasImplicitConversionTo(argType) ) { work = false; break; } } } foreach (a ; (cast(FuncDecl)s.decl).funcArgs[arg_list.length..$]) if (a.init is null) work = false; if (work) if (per) return s; else possible ~= s; } if (possible.length) return possible[0]; return null; } MessageHandler messages; }