Skip to content

Commit

Permalink
[Compiler] Improve match typing (issue rsdn#92).
Browse files Browse the repository at this point in the history
  • Loading branch information
VladD2 committed Feb 15, 2012
1 parent abe1116 commit 8e6c109
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 109 deletions.
13 changes: 8 additions & 5 deletions ncc/testsuite/negative/tyenf.n
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ enum Fruit { | Apple | Orange };

module M1 {
// bug #753
Foo() : list[string] // E: array.* is not a subtype of list.*
Foo() : list[string]
{
if (true) array(0) else null
if (true)
array(0) // E: Cannot implicitly convert type .array.+ to .list\[string\].
else
null
}

f() : void
Expand Down Expand Up @@ -59,7 +62,7 @@ module M1 {

def _x : Fruit =
if (true)
null // E: Cannot implicitly convert type 'object\+' to 'Fruit.'
null // E: Cannot implicitly convert type 'object\+' to 'Fruit'
else
Fruit.Apple;
}
Expand Down Expand Up @@ -98,7 +101,7 @@ module M1 {
public c1(a: int): int
{
if (a == 1)
() // E: Cannot implicitly convert type 'void' to 'int\+'
() // E: Cannot implicitly convert type 'void' to 'int'
else
1;
}
Expand All @@ -122,7 +125,7 @@ module M1 {
public c6(a: int) : long
{
if (a == 1)
"s" // E: Cannot implicitly convert type 'string' to 'long\+'
"s" // E: Cannot implicitly convert type 'string' to 'long'
else
1;
}
Expand Down
22 changes: 22 additions & 0 deletions ncc/testsuite/positive/Issue-git-0092.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// REFERENCE: System.Data

using System.Data.SqlTypes;
using System.Data;

public class P
{
public readonly static IDataReader _dataReader = null;

public static SqlString GetSqlString(int index)
{
// SqlString and string have a common subtype - IComparable. But we need must to use
// implicite convertion instead, as their common supertype is not compatible with the type of return value.
return _dataReader.IsDBNull(index)
? SqlString.Null // type is SqlString
: _dataReader.GetString(index); // type is string
}

static void Main()
{
}
}
174 changes: 70 additions & 104 deletions ncc/typing/Typer.n
Original file line number Diff line number Diff line change
Expand Up @@ -4215,128 +4215,94 @@ namespace Nemerle.Compiler
}
}

def hint = expected.ImplicitCastHint?.HintFast;
when (expected.ImplicitCastHint != null)
_ = expected.ImplicitCastHint.Unify(expected);

if (hint == null)
{
def canUnify =
surroundwith(speculatitveTyping)
ret :
def canUnify =
surroundwith(speculatitveTyping)
ret :
{
foreach (case in cases)
{
foreach (case in cases)
{
def body = case.body;
def caseType = body.Type;
when (!(caseType.IsConstrained || expected.IsConstrained) || !caseType.Require(expected))
ret(false);
};

true
def body = case.body;
def caseType = body.Type;
when (!(caseType.IsConstrained || expected.IsConstrained) || !caseType.Require(expected))
ret(false);
};

true
};

if (canUnify)
{
checkMatch();
if (canUnify)
{
checkMatch();

foreach (case in cases)
case.body.Type.ForceRequire(expected);
foreach (case in cases)
case.body.Type.ForceRequire(expected);

TExpr.Match(mtch.Location, null, matched_value, cases2)
}
else
{
DelayAction(mtch, expected,
Typer.DelayedLambdaAction(lastTry =>
if (lastTry)
{
checkMatch();
TExpr.Match(mtch.Location, null, matched_value, cases2)
}
else
{
DelayAction(mtch, expected,
Typer.DelayedLambdaAction(lastTry =>
if (lastTry)
{
checkMatch();

//assert2(false);
mutable hasError = false;
mutable prevTypeName = "";
mutable typeName = "";
mutable prevLoc;
mutable loc;
//assert2(false);
mutable hasError = false;
mutable prevTypeName = "";
mutable typeName = "";
mutable prevLoc;
mutable loc;

surroundwith(speculatitveTyping)
foreach (case when !IsError(case.body) in cases)
{
def caseType = case.body.Type;
loc = case.body.Location;
typeName = caseType.ToString();

unless (caseType.Require(expected))
{
hasError = true;
break;
}

prevTypeName = typeName;
prevLoc = loc;
}

when (hasError)
{
ReportLocatedError(prevLoc, messenger, $"Type of this computation branch ($prevTypeName) is incompatible with type ($(typeName )) of other branch.");
ReportLocatedError(loc, messenger, $"Type of this computation branch ($(typeName )) is incompatible with type ($prevTypeName) of other branch.");
}

None()
}
else if (Manager.DelayedTypingsInProgress && expected.IsConstrained || Manager.DelayedTypingsSecondPass)
{
surroundwith(speculatitveTyping)
foreach (case when !IsError(case.body) in cases)
{
def body = case.body;
def newBody = TryAddCastTo(body, expected);
if (newBody == null)
def caseType = case.body.Type;
loc = case.body.Location;
typeName = caseType.ToString();

unless (caseType.Require(expected))
{
ReportLocatedError(body.Location, messenger, $"Cannot implicitly convert type '$(body.Type)' to '$expected'.");
hasError = true;
break;
}
else unless (Manager.IsSpeculativeTyping)
case.body = newBody;

prevTypeName = typeName;
prevLoc = loc;
}

checkMatch();

Some(TExpr.Match(mtchLoc, expected, matched_value, cases2))

when (hasError)
{
ReportLocatedError(prevLoc, messenger, $"Type of this computation branch ($prevTypeName) is incompatible with type ($(typeName )) of other branch.");
ReportLocatedError(loc, messenger, $"Type of this computation branch ($(typeName )) is incompatible with type ($prevTypeName) of other branch.");
}
else
None(), "delayed typing of conditional expression computation branches"));
}
}
else // exists expected.ImplicitCastHint
{
def addCasts(_lastTry)
{
unless (Manager.DelayedTypingsSecondPass)
foreach (case in cases)
when (!case.body.Type.IsConstrained)
return None();

//assert2(!hint.ToString().Contains("Nemerle.Peg.Rule.Choice"));

when (expected.HintFast == null)
_ = expected.Unify(expected.ImplicitCastHint); // Provide

foreach (case when !IsError(case.body) in cases)
{
def body = case.body;
def newBody = TryAddCastTo(body, expected);
if (newBody == null)
None()
}
else if (Manager.DelayedTypingsInProgress && expected.IsConstrained || Manager.DelayedTypingsSecondPass)
{
ReportLocatedError(body.Location, messenger, $"Cannot implicitly convert type '$(body.Type)' to '$expected'.");
break;
foreach (case when !IsError(case.body) in cases)
{
def body = case.body;
def newBody = TryAddCastTo(body, expected);
if (newBody == null)
{
ReportLocatedError(body.Location, messenger, $"Cannot implicitly convert type '$(body.Type)' to '$expected'.");
break;
}
else unless (Manager.IsSpeculativeTyping)
case.body = newBody;
}

checkMatch();

Some(TExpr.Match(mtchLoc, expected, matched_value, cases2))
}
else unless (Manager.IsSpeculativeTyping)
case.body = newBody;
}

Some(TExpr.Match(mtchLoc, expected, matched_value, cases2))
}

DelayAction(mtch, expected, Typer.DelayedLambdaAction(addCasts))
else
None(), "delayed typing of conditional expression computation branches"));
}
}
}
Expand Down

0 comments on commit 8e6c109

Please sign in to comment.