Skip to content

Commit

Permalink
Implemented final overload feature.
Browse files Browse the repository at this point in the history
  * Overloads defined using the 'overload' keyword are final.

        define foo;
        overload foo(x) {}     // foo(x:T) is final
        overload foo(y:Int) {} // ambiguous match error

  * Overloads defined using the 'default' keyword can be overridden
    by subsequent 'default' definitions and 'overload's.

        define foo;
        default foo(x) = false;
        default foo(x:Int32) = true;    //OK as foo(x:T) not final
        overload foo(x:Float32) = true; //OK as foo(x:T) not final
        default foo(x:Int32) = false;  //OK as foo(x:Int32) not final

  * Default overloads may be defined in any module.

  * Standalone functions are unchanged.

Final overloads are off by default until the library has been
modified to be compatible. A compiler flag '-final-overloads' has
been added to turn final overloads on.

The library has been updated with 'default' overloads to allow
the bindgen tool and hello world example to compile with final
overloads enabled.
  • Loading branch information
agemogolk committed Jan 14, 2013
1 parent baf1bab commit 2cc3b02
Show file tree
Hide file tree
Showing 39 changed files with 248 additions and 163 deletions.
13 changes: 11 additions & 2 deletions compiler/clay.cpp
Expand Up @@ -3,7 +3,7 @@
#include "error.hpp"
#include "codegen.hpp"
#include "loader.hpp"

#include "invoketables.hpp"

// for _exit
#ifdef _WIN32
Expand Down Expand Up @@ -468,6 +468,8 @@ static void usage(char *argv0)
llvm::errs() << " -e <source> compile and run <source> (implies -run)\n";
llvm::errs() << " -M<module> \"import <module>.*;\" for -e\n";
llvm::errs() << " -version display version info\n";

llvm::errs() << " -final-overloads enable final overloads (temporary option)\n";
}

static string sharedExtensionForTarget(llvm::Triple const &triple) {
Expand Down Expand Up @@ -541,6 +543,8 @@ int main2(int argc, char **argv, char const* const* envp) {
unsigned optLevel = 2;
bool optLevelSet = false;

bool finalOverloadsEnabled = false;

#ifdef __APPLE__
genPIC = true;

Expand Down Expand Up @@ -900,6 +904,9 @@ int main2(int argc, char **argv, char const* const* envp) {
}
clayFile = argv[i];
}
else if (strcmp(argv[i], "-final-overloads") == 0) {
finalOverloadsEnabled = true;
}
else {
llvm::errs() << "error: unrecognized option " << argv[i] << '\n';
return 1;
Expand Down Expand Up @@ -955,7 +962,9 @@ int main2(int argc, char **argv, char const* const* envp) {

setInlineEnabled(inlineEnabled);
setExceptionsEnabled(exceptions);


setFinalOverloadsEnabled(finalOverloadsEnabled);

llvm::Triple llvmTriple(targetTriple);
targetTriple = llvmTriple.str();

Expand Down
5 changes: 3 additions & 2 deletions compiler/clay.hpp
Expand Up @@ -1968,6 +1968,7 @@ struct Overload : public TopLevelItem {
bool callByName:1;
bool nameIsPattern:1;
bool hasAsConversion:1;
bool isDefault:1;

Overload(Module *module, ExprPtr target,
CodePtr code,
Expand All @@ -1976,7 +1977,7 @@ struct Overload : public TopLevelItem {
: TopLevelItem(OVERLOAD, module), target(target), code(code),
isInline(isInline), patternsInitializedState(0),
callByName(callByName), nameIsPattern(false),
hasAsConversion(false) {}
hasAsConversion(false), isDefault(false) {}
Overload(Module *module, ExprPtr target,
CodePtr code,
bool callByName,
Expand All @@ -1985,7 +1986,7 @@ struct Overload : public TopLevelItem {
: TopLevelItem(OVERLOAD, module), target(target), code(code),
isInline(isInline), patternsInitializedState(0),
callByName(callByName), nameIsPattern(false),
hasAsConversion(hasAsConversion) {}
hasAsConversion(hasAsConversion), isDefault(false) {}
};

struct Procedure : public TopLevelItem {
Expand Down
24 changes: 24 additions & 0 deletions compiler/error.cpp
Expand Up @@ -305,6 +305,30 @@ void argumentError(size_t index, llvm::StringRef msg) {
error(sout.str());
}

void ambiguousMatchError(MatchSuccessPtr match, MatchSuccessPtr match2) {
if (match->overload->location.ok()) {
unsigned line, column;
displayLocation(match->overload->location, line, column);
llvm::errs() << match->overload->location.source->fileName
<< '(' << line+1 << ',' << column << "): " << "found matching overload\n";
llvm::errs().flush();

}
if (match2->overload->location.ok()) {
unsigned line, column;
displayLocation(match2->overload->location, line, column);
llvm::errs() << match2->overload->location.source->fileName
<< '(' << line+1 << ',' << column << "): " << "error: ambiguous overload\n";
llvm::errs().flush();

}
string buf;
llvm::raw_string_ostream err(buf);
err << "ambiguous overloads for call-site\n";

error(err.str());
}

static const char *valuesStr(size_t n) {
return (n == 1) ? "value" : "values";
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/error.hpp
Expand Up @@ -2,6 +2,7 @@
#define __ERROR_HPP

#include "clay.hpp"
#include "invoketables.hpp"

namespace clay {

Expand All @@ -11,6 +12,7 @@ extern set<pair<string,string> > logMatchSymbols;
void matchBindingError(MatchResultPtr const &result);
void matchFailureLog(MatchFailureError const &err);
void matchFailureError(MatchFailureError const &err);
void ambiguousMatchError(MatchSuccessPtr match, MatchSuccessPtr match2);

class CompilerError : std::exception {
};
Expand Down
45 changes: 39 additions & 6 deletions compiler/invoketables.cpp
Expand Up @@ -12,6 +12,13 @@

namespace clay {

static bool _finalOverloadsEnabled = false;

void setFinalOverloadsEnabled(bool enabled)
{
_finalOverloadsEnabled = enabled;
}


//
// callableOverloads
Expand Down Expand Up @@ -314,8 +321,8 @@ static InvokeEntry* newInvokeEntry(InvokeSet* parent,
MatchSuccessPtr interfaceMatch)
{
InvokeEntry* entry = new InvokeEntry(parent, match->callable, match->argsKey);
entry->origCode = match->code;
entry->code = clone(match->code);
entry->origCode = match->overload->code;
entry->code = clone(match->overload->code);
entry->env = match->env;
if (interfaceMatch != NULL)
entry->interfaceEnv = interfaceMatch->env;
Expand All @@ -324,8 +331,8 @@ static InvokeEntry* newInvokeEntry(InvokeSet* parent,
entry->varArgName = match->varArgName;
entry->varArgTypes = match->varArgTypes;
entry->varArgPosition = match->varArgPosition;
entry->callByName = match->callByName;
entry->isInline = match->isInline;
entry->callByName = match->overload->callByName;
entry->isInline = match->overload->isInline;

return entry;
}
Expand Down Expand Up @@ -381,9 +388,9 @@ InvokeEntry* lookupInvokeEntry(ObjectPtr callable,

unsigned i = 0;
while ((match = getMatch(invokeSet,i,failures)).ptr() != NULL) {
if (matchTempness(match->code,
if (matchTempness(match->overload->code,
argsTempness,
match->callByName,
match->overload->callByName,
tempnessKey,
forwardedRValueFlags))
{
Expand All @@ -407,6 +414,32 @@ InvokeEntry* lookupInvokeEntry(ObjectPtr callable,
invokeSet->tempnessMap2[tempnessKey] = entry;
invokeSet->tempnessMap[argsTempness] = entry;

if (_finalOverloadsEnabled) {
MatchSuccessPtr match2;
vector<ValueTempness> tempnessKey2;
vector<uint8_t> forwardedRValueFlags2;
MatchFailureError failures2;
unsigned j = invokeSet->nextOverloadIndex;
while ((match2 = findMatchingInvoke(callableOverloads(callable),
j,
callable,
argsKey,
failures2)).ptr() != NULL) {
if (matchTempness(match2->overload->code,
argsTempness,
match2->overload->callByName,
tempnessKey2,
forwardedRValueFlags2))
{
break;
}
++j;
}

if (match2 != NULL && !match2->overload->isDefault)
ambiguousMatchError(match, match2);
}

return entry;
}

Expand Down
1 change: 1 addition & 0 deletions compiler/invoketables.hpp
Expand Up @@ -125,6 +125,7 @@ InvokeEntry* lookupInvokeEntry(ObjectPtr callable,
llvm::ArrayRef<ValueTempness> argsTempness,
MatchFailureError &failures);

void setFinalOverloadsEnabled(bool enabled);

}

Expand Down
3 changes: 2 additions & 1 deletion compiler/lexer.cpp
Expand Up @@ -132,7 +132,8 @@ static void initKeywords() {
const char *s[] =
{"public", "private", "import", "as",
"record", "variant", "instance",
"define", "overload", "external", "alias",
"define", "overload", "default",
"external", "alias",
"rvalue", "ref", "forward",
"inline", "noinline", "forceinline",
"enum", "var", "and", "or", "not",
Expand Down
7 changes: 3 additions & 4 deletions compiler/matchinvoke.cpp
Expand Up @@ -161,12 +161,11 @@ MatchResultPtr matchInvoke(OverloadPtr overload,
if (code->predicate.ptr())
if (!evaluateBool(code->predicate, staticEnv))
return new MatchPredicateError(code->predicate);

MatchSuccessPtr result = new MatchSuccess(
overload->callByName, overload->isInline, code, staticEnv,
callable, argsKey
overload, staticEnv, callable, argsKey
);

for (unsigned i = 0, j = 0; i < formalArgs.size(); ++i) {
FormalArgPtr x = formalArgs[i];
if (x->varArg) {
Expand Down
9 changes: 4 additions & 5 deletions compiler/matchinvoke.hpp
Expand Up @@ -27,7 +27,7 @@ struct MatchResult : public Object {
};

struct MatchSuccess : public MatchResult {
CodePtr code;
OverloadPtr overload;
EnvPtr env;

ObjectPtr callable;
Expand All @@ -42,12 +42,11 @@ struct MatchSuccess : public MatchResult {
InlineAttribute isInline:3;
bool callByName:1;

MatchSuccess(bool callByName, InlineAttribute isInline, CodePtr code, EnvPtr env,
MatchSuccess(OverloadPtr overload, EnvPtr env,
ObjectPtr callable, llvm::ArrayRef<TypePtr> argsKey)
: MatchResult(MATCH_SUCCESS),
code(code), env(env), callable(callable),
argsKey(argsKey), varArgPosition(0),
isInline(isInline), callByName(callByName) {}
overload(overload), env(env), callable(callable),
argsKey(argsKey), varArgPosition(0) {}
};
typedef Pointer<MatchSuccess> MatchSuccessPtr;

Expand Down
24 changes: 19 additions & 5 deletions compiler/parser.cpp
Expand Up @@ -2359,6 +2359,18 @@ static bool allReturnSpecs(vector<ReturnSpecPtr> &returnSpecs,
// define, overload
//

static bool isOverload(bool &isDefault) {
int p = save();
if (keyword("overload"))
isDefault = false;
else if (restore(p), keyword("default"))
isDefault = true;
else {
return false;
}
return true;
}

static bool optInline(InlineAttribute &isInline) {
unsigned p = save();
if (keyword("inline"))
Expand Down Expand Up @@ -2553,7 +2565,8 @@ static bool overload(TopLevelItemPtr &x, Module *module, unsigned s) {
if (!optInline(isInline)) return false;
bool callByName;
if (!optCallByName(callByName)) return false;
if (!keyword("overload")) return false;
bool isDefault;
if (!isOverload(isDefault)) return false;
unsigned e = save();
restore(s);
Location location = currentLocation();
Expand Down Expand Up @@ -2585,9 +2598,10 @@ static bool overload(TopLevelItemPtr &x, Module *module, unsigned s) {
target->startLocation = targetStartLocation;
target->endLocation = targetEndLocation;
code->location = location;
x = new Overload(module, target, code, callByName, isInline, hasAsConversion);
x->location = location;
NameRefPtr name = (NameRef *)target.ptr();
OverloadPtr oload = new Overload(module, target, code, callByName, isInline, hasAsConversion);
oload->location = location;
oload->isDefault = isDefault;
x = oload.ptr();
return true;
}

Expand Down Expand Up @@ -3028,7 +3042,7 @@ static bool documentationAnnotation(std::map<DocumentationAnnotation, string> &a
ano = SectionAnnotation;
} else if (key == "module") {
ano = ModuleAnnotation;
} else if (key == "overload") {
} else if (key == "overload" || key == "default") {
ano = OverloadAnnotation;
} else if (key == "record") {
ano = RecordAnnotion;
Expand Down
2 changes: 1 addition & 1 deletion lib-clay/core/characters/characters.clay
Expand Up @@ -9,7 +9,7 @@ record UniChar (code:UInt32);
[T]
define Character?(#T) : Bool;

overload Character?(x) : Bool = false;
default Character?(x) : Bool = false;
overload Character?(#Char) : Bool = true;
overload Character?(#UniChar) : Bool = true;

Expand Down
2 changes: 1 addition & 1 deletion lib-clay/core/coordinates/coordinates.clay
Expand Up @@ -18,7 +18,7 @@ LValueCoordinate?(T) : Bool =
[T]
define ContiguousCoordinate?(#T) : Bool;

overload ContiguousCoordinate?(T) : Bool = false;
default ContiguousCoordinate?(T) : Bool = false;



Expand Down
4 changes: 2 additions & 2 deletions lib-clay/core/errors/backtrace/platform/platform.unix.clay
Expand Up @@ -15,7 +15,7 @@ define printBacktraceToStderr(backtrace: Backtrace) :;

define captureBacktrace(): Backtrace;

forceinline overload captureBacktrace() --> returned: Backtrace {
forceinline default captureBacktrace() --> returned: Backtrace {
returned.size = 0;
}

Expand All @@ -26,7 +26,7 @@ forceinline overload captureBacktrace() --> returned: Backtrace {
Int(size(returned.callstack)));
}

forceinline overload printBacktraceToStderr(backtrace: Backtrace) : { }
forceinline default printBacktraceToStderr(backtrace: Backtrace) : { }

[when BacktraceSupported?]
overload printBacktraceToStderr(bt: Backtrace) : {
Expand Down
4 changes: 2 additions & 2 deletions lib-clay/core/errors/errors.clay
Expand Up @@ -55,14 +55,14 @@ record assert[..tags] ();
[..tags]
alias overload assert[..tags](..whatever) : {}

alias overload assert(..whatever) : {}
alias default assert(..whatever) : {}

[file, line, column, cond]
private assertStringLiteral(#file, #line, #column, #cond, ..etc)
= strl(#file, "(", #line, ",", #column, "): assertion ", #cond, " failed", ..etc);

[when AllAssertionsEnabled?()]
alias overload assert(cond:Bool) : {
alias default assert(cond:Bool) : {
if (not likely(cond))
errorWithPrintfNoThrow(
assertStringLiteral(__FILE__, #__LINE__, #__COLUMN__, __ARG__ cond));
Expand Down
4 changes: 2 additions & 2 deletions lib-clay/core/exceptions/exceptions.clay
Expand Up @@ -58,7 +58,7 @@ private exceptionObject(exp:RawPointer) : ByRef[ExceptionData]
// more sophisticated version.
define printUnhandledExceptionToStderr(e) :;

overload printUnhandledExceptionToStderr(e) : {
default printUnhandledExceptionToStderr(e) : {
libc.fprintf(libc.stderr, cstring("unhandled %s exception\n"), cstring(MemberTypeName(e)));
}

Expand All @@ -67,7 +67,7 @@ overload printUnhandledExceptionToStderr(e) : {
/// @section throwValue, continueException

[T when Type?(T)]
overload throwValue(x:T, ..ignored) : {
default throwValue(x:T, ..ignored) : {
errorWithPrintfNoThrow(stringLiteralConcat("exception of type ", StaticName(T)," thrown with exceptions disabled"));
}

Expand Down
4 changes: 2 additions & 2 deletions lib-clay/core/maybe/maybe.clay
Expand Up @@ -38,8 +38,8 @@ forceinline overload just(m: Maybe[T], dflt: T) = maybe(m, v => v, () => dflt);
/// @section maybe function

private define maybeValue;
forceinline overload maybeValue(T, forward x, thenFn, ..elseFn) = forward ..thenFn(x);
forceinline overload maybeValue(T, forward n: Nothing, thenFn, elseFn) = forward ..elseFn();
forceinline default maybeValue(T, forward x, thenFn, ..elseFn) = forward ..thenFn(x);
forceinline default maybeValue(T, forward n: Nothing, thenFn, elseFn) = forward ..elseFn();


// if the thenFn returns Maybe[T]s, have the default else case return nothing(T)s
Expand Down

0 comments on commit 2cc3b02

Please sign in to comment.