From 6a974fbc30556e74f3db7144a6f4213e76c43b21 Mon Sep 17 00:00:00 2001 From: zhiayang Date: Fri, 11 Oct 2019 10:39:49 +0800 Subject: [PATCH] fix lvalue poof when calling method on rvalues --- build/ultratiny.flx | 38 ++++++++++++++++++++++++++++++------ source/codegen/dotop.cpp | 9 +++++++++ source/frontend/errors.cpp | 6 ++++++ source/include/utils.h | 8 +++++++- source/typecheck/classes.cpp | 8 +++----- source/typecheck/dotop.cpp | 3 ++- 6 files changed, 59 insertions(+), 13 deletions(-) diff --git a/build/ultratiny.flx b/build/ultratiny.flx index 268a444e..138e51a0 100644 --- a/build/ultratiny.flx +++ b/build/ultratiny.flx @@ -58,9 +58,10 @@ class Z: Y class A { init() { } - virtual fn foo(a: Y) -> Y + virtual fn lol(a: Y) -> &Y { - return Y(c: 471) + std::io::println("A::foo()") + return alloc Y(c: 471) } } @@ -68,21 +69,46 @@ class B : A { init() : super() { } - override fn foo(a: Y) -> Y + override fn foo(a: Y) -> &Y { - return Y(c: 748) + std::io::println("B::foo()") + return alloc Z(c: 748) + // return 3 } } +// import std::io as _ + +// @entry fn main() +// { +// println("hello, world!") +// } + +// issue #0: we basically don't really even check for overriding methods properly. // issue #1: co/contra-variance of return and parameter types for virtual methods // issue #2: crashes when initialisers have default arguments?? // classes are a Bad Idea (tm) ): +struct Tmp +{ + k: int + m: int + + fn meth() -> int => k * m +} + @entry fn main() { - let a = B() - let q = a.foo(Y(c: 1)).data + // let a = B() + // let q = a.foo(Y(c: 1)).data + + // let y: &X = alloc Y(c: 41) + // std::io::println("y = %", y.data) + + // let q = Tmp(k: 3, m: 7).meth() + + // let q = B().foo(Y(c: 1)).data std::io::println("thing: %", q) } diff --git a/source/codegen/dotop.cpp b/source/codegen/dotop.cpp index 3e8d67de..8f136a16 100644 --- a/source/codegen/dotop.cpp +++ b/source/codegen/dotop.cpp @@ -62,6 +62,15 @@ CGResult sst::MethodDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) fir::Type* sty = 0; auto res = getAppropriateValuePointer(cs, this, this->lhs, &sty); + if(!res->islvalue()) + { + auto tmplval = cs->irb.CreateLValue(this->lhs->type); + cs->irb.Store(res.value, tmplval); + + res.value = tmplval; + res->makeConst(); + } + // then we insert it as the first argument auto rv = util::pool(this->loc, res.value->getType()->getMutablePointerTo()); rv->rawValue = CGResult(cs->irb.AddressOf(res.value, true)); diff --git a/source/frontend/errors.cpp b/source/frontend/errors.cpp index de96e8c1..050c7a67 100644 --- a/source/frontend/errors.cpp +++ b/source/frontend/errors.cpp @@ -467,6 +467,7 @@ void OverloadError::post() + [[noreturn]] void doTheExit(bool trace) { fprintf(stderr, "there were errors, compilation cannot continue\n"); @@ -487,3 +488,8 @@ void OverloadError::post() + + + + + diff --git a/source/include/utils.h b/source/include/utils.h index 7f39a6b2..d265a6a8 100644 --- a/source/include/utils.h +++ b/source/include/utils.h @@ -171,7 +171,13 @@ namespace util template std::vector take(const std::vector& v, size_t num) { - return std::vector(v.begin(), v.begin() + num); + return std::vector(v.begin(), v.begin() + std::min(num, v.size())); + } + + template + std::vector drop(const std::vector& v, size_t num) + { + return std::vector(v.begin() + std::min(num, v.size()), v.end()); } inline std::string join(const std::vector& list, const std::string& sep) diff --git a/source/typecheck/classes.cpp b/source/typecheck/classes.cpp index 5a0c108a..48752a45 100644 --- a/source/typecheck/classes.cpp +++ b/source/typecheck/classes.cpp @@ -209,13 +209,11 @@ TCResult ast::ClassDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, co { // ok -- issue is that we cannot compare the method signatures directly -- because the method will take the 'self' of its // respective class, meaning they won't be duplicates. so, we must compare without the first parameter. - - // note: we're passing by copy here intentionally so we can erase the first one. - auto compareMethods = [&fs](std::vector a, std::vector b) -> bool { - return fs->isDuplicateOverload(a, b); + auto compareMethodSignatures = [&fs](const std::vector& a, const std::vector& b) -> bool { + return fs->isDuplicateOverload(util::drop(a, 1), util::drop(b, 1)); }; - if(bf->id.name == meth->id.name && compareMethods(bf->params, meth->params)) + if(bf->id.name == meth->id.name && compareMethodSignatures(bf->params, meth->params)) { // check for virtual functions. //* note: we don't need to care if 'bf' is the base method, because if we are 'isOverride', then we are also diff --git a/source/typecheck/dotop.cpp b/source/typecheck/dotop.cpp index df9944b7..1df3b6e7 100644 --- a/source/typecheck/dotop.cpp +++ b/source/typecheck/dotop.cpp @@ -462,8 +462,9 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d // ok. auto defn = fs->typeDefnMap[type]; - iceAssert(defn); + // note: if `defn` is null, then all the dcasts will fail and we'll + // fallthrough to the bottom. if(auto str = dcast(sst::StructDefn, defn)) { // right.