Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Correctly handle references to references, plus some code cleaning. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
ba909d1a948a6dfd7c1101a29e337c83 |
| User & Date: | achavasse 2021-02-01 12:56:55.675 |
Context
|
2021-02-01
| ||
| 19:26 | Added a rule based system to pretty print EIR expressions in a less horrific way. check-in: 6675f81702 user: achavasse tags: trunk | |
| 12:56 | Correctly handle references to references, plus some code cleaning. check-in: ba909d1a94 user: achavasse tags: trunk | |
|
2021-01-21
| ||
| 21:05 | Removed the vector "typechecking rule", whose existence made no sense. Typechecking rules should operate only on values and pattern of values. Typechecking multiple values against multiple params is now done through a specific function instead. check-in: 7b9f645074 user: achavasse tags: trunk | |
Changes
Changes to bs/builtins/types/func/bfunc.inl.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 |
case sema::Env::Status::NoMatch:
pOvlSet = make_shared< OverloadSet >( identity );
env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
break;
case sema::Env::Status::AmbiguousMatch:
| | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
case sema::Env::Status::NoMatch:
pOvlSet = make_shared< OverloadSet >( identity );
env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
break;
case sema::Env::Status::AmbiguousMatch:
G_ERROR( "ambiguous match while registering builtin func "s + name.str() );
}
return RegisterBuiltinFunc< FT >( env, pOvlSet, forward< F >( func ) );
}
template< typename FT, typename F >
ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, ptr< OverloadSet > pOvlSet, F&& func )
{
auto fvi = make_shared< builtins::FuncVerificationInfos >( RootIdentity() );
if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetFuncInvocationRule() ) )
G_ERROR( "duplicate overload registered for builtin func." );
return fvi;
}
}
namespace goose::eir
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/func.cpp.
| ︙ | ︙ | |||
130 131 132 133 134 135 136 |
Term BuildArgListForCall( const FuncType& ft, const Term& unifiedArgs )
{
auto av = make_shared< Vector >();
av->reserve( VecSize( ft.params() ) );
ForEachInVectorTerms( ft.params(), unifiedArgs, [&]( auto&& p, auto&& a )
{
| | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
Term BuildArgListForCall( const FuncType& ft, const Term& unifiedArgs )
{
auto av = make_shared< Vector >();
av->reserve( VecSize( ft.params() ) );
ForEachInVectorTerms( ft.params(), unifiedArgs, [&]( auto&& p, auto&& a )
{
auto vp = ValuePatternFromEIR( p );
if( vp->val() == HOLE( "_"_sid ) )
av->append( a );
return true;
} );
return av;
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/lower.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
ForEachInVectorTerm( ft.params(), [&]( auto&& p )
{
// Params are not stored explicitely, but as patterns
// for expediency (where the value is either a hole or an actual
// value depending on whether this is a specialization param),
// which is useful in most places except here as we need to extract
// back the type from the pattern (and skip specialization params).
| | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
ForEachInVectorTerm( ft.params(), [&]( auto&& p )
{
// Params are not stored explicitely, but as patterns
// for expediency (where the value is either a hole or an actual
// value depending on whether this is a specialization param),
// which is useful in most places except here as we need to extract
// back the type from the pattern (and skip specialization params).
auto vp = ValuePatternFromEIR( p );
if( !vp )
{
success = false;
return false;
}
if( vp->val() == HOLE( "_"_sid ) )
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/typecheck.cpp.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *ValuePatternFromEIR( lhs );
lhsVal.sort() = HOLE( "_"_sid );
co_yield Unify( ValueToEIR( lhsVal ), rhs, tcc );
} );
// Constant param rule
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *ValuePatternFromEIR( lhs );
auto rhsVal = *ValuePatternFromEIR( rhs );
// Unify the types
for( auto&& [ut,tcc] : Unify( lhsVal.type(), rhsVal.type(), tcc ) )
{
// Unify the contents
for( auto&& [uv,tcc] : Unify( lhsVal.val(), rhsVal.val(), tcc ) )
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/typecheck.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupLocalVarTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
| < < < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupLocalVarTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
// LocalVar type checking against another LocalVar: unify their types.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( localVarPattern ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lvarType = *FromValue< LocalVarType >( *ValueFromEIR( ValuePatternFromEIR( lhs )->type() ) );
auto rhsVal = *ValuePatternFromEIR( rhs );
auto rvarType = *FromValue< LocalVarType >( *ValueFromEIR( rhsVal.type() ) );
for( auto&& [s, tcc] : Unify( lvarType.type(), rvarType.type(), tcc ) )
{
co_yield { ValueToEIR( Value( ValueToEIR( ToValue( LocalVarType( s ) ) ),
rhsVal.val() ) ), tcc };
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/overloadset/helpers.cpp.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 |
switch( env.retrieveValue( identity, RootIdentity(), result ) )
{
case sema::Env::Status::Success:
return *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );
case sema::Env::Status::NoMatch:
| | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
switch( env.retrieveValue( identity, RootIdentity(), result ) )
{
case sema::Env::Status::Success:
return *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );
case sema::Env::Status::NoMatch:
G_ERROR( format( "fatal: overload set {} not found", name ) );
case sema::Env::Status::AmbiguousMatch:
G_ERROR( format( "fatal: ambiguous match for overload set {}", name ) );
}
return nullptr;
}
ptr< OverloadSet > GetOrCreateOverloadSet( Env& env, const StringId& name )
{
|
| ︙ | ︙ | |||
47 48 49 50 51 52 53 |
{
auto pOvlSet = make_shared< OverloadSet >( identity );
env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
return pOvlSet;
}
case sema::Env::Status::AmbiguousMatch:
| | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
{
auto pOvlSet = make_shared< OverloadSet >( identity );
env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
return pOvlSet;
}
case sema::Env::Status::AmbiguousMatch:
G_ERROR( format( "fatal: ambiguous match for overload set {}", name ) );
}
return nullptr;
}
Value InvokeOverloadSet( const Context& c, const ptr< OverloadSet >& pOvlSet, Value args )
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/param.h.
1 2 3 4 5 6 7 8 |
#ifndef GOOSE_BUILTINS_TYPES_PARAM_H
#define GOOSE_BUILTINS_TYPES_PARAM_H
namespace goose::builtins
{
template< typename T, typename V >
auto ParamPat( T&& type, V&& val )
{
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#ifndef GOOSE_BUILTINS_TYPES_PARAM_H
#define GOOSE_BUILTINS_TYPES_PARAM_H
namespace goose::builtins
{
template< typename T, typename V >
auto ParamPat( T&& type, V&& val )
{
// If the type is a tuple of types, convert it to the type of a tuple.
// (the type of a tuple is just a list of values, so just extract the value part of the tuple)
if( auto typeVal = ValueFromEIR( type ); typeVal && IsTuple( *typeVal ) )
return ValueToEIR( Value( ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );
return ValueToEIR( Value( forward< T >( type ), forward< V >( val ) ) );
}
template< typename T >
auto ParamPat( T&& type )
{
// If the type is a tuple of types, convert it to the type of a tuple.
// (the type of a tuple is just a list of values, so just extract the value part of the tuple)
if( auto typeVal = ValueFromEIR( type ); typeVal && IsTuple( *typeVal ) )
return ValueToEIR( ValuePattern( HOLE( "_"_sid ), ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );
return ValueToEIR( ValuePattern( TSID( param ), forward< T >( type ), HOLE( "_"_sid ) ) );
}
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/reference/reference.cpp.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
return pattern;
}
// Returns an instruction that computes the address of whatever's contained in the locvar.
// If the locvar contains a reference, this will return what's referenced by it. (TODO)
ptr< cir::Instruction > GetAddrFromLocalVar( const LocalVar& lv )
{
| < < < < < < < < < < < < < < < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
return pattern;
}
// Returns an instruction that computes the address of whatever's contained in the locvar.
// If the locvar contains a reference, this will return what's referenced by it. (TODO)
ptr< cir::Instruction > GetAddrFromLocalVar( const LocalVar& lv )
{
return make_shared< cir::Instruction >( cir::VarAddr( lv.index() ) );
}
Value BuildLocalVarMutRef( const LocalVar& lv )
{
auto rt = ValueToEIR( ToValue( ReferenceType{ lv.type(), TSID( mut ) } ) );
return BuildComputedValue( move( rt ), cir::VarAddr( lv.index() ) );
}
}
namespace goose::eir
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/reference/typecheck.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupReferenceTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
auto refTypePattern = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
auto refTypePatternConstant = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( const ), ANYTERM( _ ) ) ) );
auto refTypePatternMutable = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( mut ), ANYTERM( _ ) ) ) );
auto refTypePatternTemporary = ValueToEIR(
| > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace
{
using namespace goose::builtins;
TCGen TypeCheckingDereference( const Term& lhs, const Term& rhs, TypeCheckingContext tcc )
{
auto refval = *ValueFromEIR( rhs );
G_VAL_ASSERT( refval, !refval.isConstant() );
auto refType = FromValue< ReferenceType >( *ValueFromEIR( refval.type() ) );
if( !refType )
co_return;
auto content = ValueToEIR( BuildComputedValue( refType->type(),
cir::Load( refval.cir(), refType->type() ) )
.setLocationId( refval.locationId() ) );
// TypeCheck the param with the ref's content
co_yield TypeCheck( lhs, content, tcc );
}
}
namespace goose::builtins
{
void SetupReferenceTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
auto refTypePattern = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
auto refRefTypePattern = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), refTypePattern ) ) );
auto refTypePatternConstant = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( const ), ANYTERM( _ ) ) ) );
auto refTypePatternMutable = ValueToEIR(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( mut ), ANYTERM( _ ) ) ) );
auto refTypePatternTemporary = ValueToEIR(
|
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lRefType = *FromValue< ReferenceType >( *ValueFromEIR( ValuePatternFromEIR( lhs )->type() ) );
auto rhsVal = *ValuePatternFromEIR( rhs );
auto rRefType = *FromValue< ReferenceType >( *ValueFromEIR( rhsVal.type() ) );
// Unify the behaviors
for( auto&& [b, tcc] : Unify( lRefType.behavior(), rRefType.behavior(), tcc ) )
{
// Unify the types
for( auto&& [t, tcc] : Unify( lRefType.type(), rRefType.type(), tcc ) )
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
ANYTERM( _ ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
| | > | | < > > > < | < | > | | < | | | < < < < < < < < | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
ANYTERM( _ ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
TypeCheckingDereference
);
// Implicit dereferencing of references to references:
// We need to define this one explicitely, otherwise it gets
// preempted by the reference type checking rule
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( refTypePattern ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refRefTypePattern,
ANYTERM( _ ) ) ),
TypeCheckingDereference
);
// LocalVar type checking against a param (implicit referencing)
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltype = ValuePatternFromEIR( lhs )->type();
auto lvval = *ValueFromEIR( rhs );
auto locvar = FromValue< LocalVar >( lvval );
if( !locvar )
co_return;
auto ref = ValueToEIR( ToValue( BuildLocalVarMutRef( *locvar ) )
|
| ︙ | ︙ | |||
166 167 168 169 170 171 172 |
{
if( !tcc.context().codeBuilder() )
co_return;
if( !tcc.context().codeBuilder()->cfg() )
co_return;
| | | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
{
if( !tcc.context().codeBuilder() )
co_return;
if( !tcc.context().codeBuilder()->cfg() )
co_return;
auto lRefType = *FromValue< ReferenceType >( *ValueFromEIR( ValuePatternFromEIR( lhs )->type() ) );
auto lhsPat = ValueToEIR( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );
for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )
{
auto valPat = *ValuePatternFromEIR( s );
ReferenceType rt( valPat.type(), TSID( temp ) );
auto refPat = ValueToEIR( ValuePattern( HOLE( "_"_sid ), ValueToEIR( ToValue( rt ) ), HOLE( "_"_sid ) ) );
// TypeCheck the param with the ref
for( auto&& [s,tcc] : TypeCheck( lhs, refPat, tcc ) )
{
|
| ︙ | ︙ | |||
196 197 198 199 200 201 202 |
)
);
assert( result );
auto&& [ref, rhs] = *result;
auto rhsVal = *ValueFromEIR( rhs );
| | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
)
);
assert( result );
auto&& [ref, rhs] = *result;
auto rhsVal = *ValueFromEIR( rhs );
auto refPat = *ValuePatternFromEIR( ref );
auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
return ValueToEIR( BuildComputedValue( refPat.type(), TempAddr( tempIndex, rhsVal ) ) );
} );
co_yield { move( wrapped ), tcc };
}
}
} );
}
}
|
Changes to bs/builtins/types/runtime/typecheck.cpp.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
// It means that we are unifying a function parameter against any ct_int value,
// which we can't (because we have to know the value to safely convert it),
// so we reject it.
auto rhsVal = *ValueFromEIR( rhs );
if( !rhsVal.isConstant() )
co_return;
| | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
// It means that we are unifying a function parameter against any ct_int value,
// which we can't (because we have to know the value to safely convert it),
// so we reject it.
auto rhsVal = *ValueFromEIR( rhs );
if( !rhsVal.isConstant() )
co_return;
auto lhsVal = ValuePatternFromEIR( lhs );
if( !lhsVal )
co_return;
auto s = HalfUnify( lhsVal->type(), tcc );
if( !s )
co_return;
|
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
ANYTERM( _ ),
GetValueType< string >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
auto str = *FromValue< string >( *ValueFromEIR( rhs ) );
| | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
ANYTERM( _ ),
GetValueType< string >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
auto str = *FromValue< string >( *ValueFromEIR( rhs ) );
auto lhsVal = *ValuePatternFromEIR( lhs );
co_yield { ValueToEIR(
BuildComputedValue( lhsVal.type(), cir::LoadConstStr( str ) ) ), c };
} );
auto ptrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
ANYTERM( _ ) ) );
|
| ︙ | ︙ | |||
182 183 184 185 186 187 188 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
GetValueType< NullPointer >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
| | | 182 183 184 185 186 187 188 189 190 191 192 193 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
GetValueType< NullPointer >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
auto lVal = *ValuePatternFromEIR( lhs );
co_yield { ValueToEIR( Value( lVal.type(), 0U ) ), c };
} );
}
}
|
Changes to bs/builtins/types/tuple/typecheck.cpp.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 |
auto argType = GetTupleElementType( tupArg, index );
auto arg = GetTupleElement( tupArg, index );
auto tupSize = TupleSize( tupArg );
for( auto&& [s,tcc] : TypeCheck( param, arg, tcc ) )
{
| | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
auto argType = GetTupleElementType( tupArg, index );
auto arg = GetTupleElement( tupArg, index );
auto tupSize = TupleSize( tupArg );
for( auto&& [s,tcc] : TypeCheck( param, arg, tcc ) )
{
auto val = ValuePatternFromEIR( s );
assert( val );
auto newOut = AppendToTuple( out, *val );
if( index == ( tupSize - 1 ) )
co_yield { ValueToEIR( newOut ), tcc };
else
co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
|
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
auto argRef = ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ),
move( argAddr ) ) );
auto tupSize = TupleTypeSize( tupType );
for( auto&& [s,tcc] : TypeCheck( param, argRef, tcc ) )
{
| | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
auto argRef = ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ),
move( argAddr ) ) );
auto tupSize = TupleTypeSize( tupType );
for( auto&& [s,tcc] : TypeCheck( param, argRef, tcc ) )
{
auto val = ValuePatternFromEIR( s );
assert( val );
auto newOut = AppendToTuple( out, *val );
if( index == ( tupSize - 1 ) )
co_yield { ValueToEIR( newOut ), tcc };
else
co_yield TypeCheckComputedTuple( tcc, tupType, tupArg, tupArgRef, index + 1, newOut );
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
ValueToEIR( ValuePattern(
TSID( constant ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
VECOFLENGTH( L ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
ValueToEIR( ValuePattern(
TSID( constant ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
VECOFLENGTH( L ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = ValuePatternFromEIR( lhs );
auto rtup = ValueFromEIR( rhs );
if( !ltup || !rtup )
co_return;
auto tupType = *ValueFromEIR( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleSize( *rtup ) );
|
| ︙ | ︙ | |||
93 94 95 96 97 98 99 |
ValueToEIR( ValuePattern(
TSID( computed ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
ValueToEIR( ValuePattern(
TSID( computed ),
ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = ValuePatternFromEIR( lhs );
auto rtup = ValueFromEIR( rhs );
if( !ltup || !rtup || !tcc.context().codeBuilder() )
co_return;
auto tupType = *ValueFromEIR( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromEIR( rtup->type() ) ) );
|
| ︙ | ︙ |
Changes to bs/diagnostics/diagnosticsmanager.h.
| ︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 78 79 |
unordered_map< CustomDiagIdentifier, string > m_customDiagnostics;
bool m_emittedFirstError = false;
bool m_forceColors = false;
bool m_traceMode = false;
};
}
#define G_VAL_ASSERT( val, cond ) \
if( !( cond ) ) \
{ \
| > > > > > > > > > > > > > > | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
unordered_map< CustomDiagIdentifier, string > m_customDiagnostics;
bool m_emittedFirstError = false;
bool m_forceColors = false;
bool m_traceMode = false;
};
}
#define G_ERROR( message ) \
{ \
DiagnosticsManager::GetInstance().emitErrorMessage( 0, \
::fmt::format( "Internal error: {}:{}: {}", __FILE__, __LINE__, message ) ); \
abort(); \
}
#define G_VAL_ERROR( val, message ) \
{ \
DiagnosticsManager::GetInstance().emitErrorMessage( (val).locationId(), \
::fmt::format( "Internal error: {}:{}: {}", __FILE__, __LINE__, message ) ); \
abort(); \
}
#define G_VAL_ASSERT( val, cond ) \
if( !( cond ) ) \
{ \
DiagnosticsManager::GetInstance().emitErrorMessage( (val).locationId(), \
::fmt::format( "Internal error: {}:{}: assertion " #cond " failed", __FILE__, __LINE__ ) ); \
abort(); \
}
#endif
|
Changes to bs/eir/match.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#ifndef GOOSE_EIR_MATCH_H
#define GOOSE_EIR_MATCH_H
namespace goose::eir
{
class MatchSolution
{
public:
size_t complexity() const { return m_complexity; }
size_t numVars() const;
template< typename T >
const T* getVar( const StringId& name ) const
{
if( name == "_"_sid )
return nullptr;
| > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#ifndef GOOSE_EIR_MATCH_H
#define GOOSE_EIR_MATCH_H
namespace goose::eir
{
struct MatchScore
{
size_t m_complexity = 0;
size_t m_numVars = 0;
bool operator<( const MatchScore& rhs ) const
{
if( m_complexity != rhs.m_complexity )
return m_complexity < rhs.m_complexity;
return m_numVars > rhs.m_numVars;
}
bool operator>( const MatchScore& rhs ) const
{
if( m_complexity != rhs.m_complexity )
return m_complexity > rhs.m_complexity;
return m_numVars < rhs.m_numVars;
}
};
class MatchSolution
{
public:
size_t complexity() const { return m_complexity; }
size_t numVars() const;
MatchScore score() const { return MatchScore{ m_complexity, m_pVars ? m_pVars->size() : 0 }; }
template< typename T >
const T* getVar( const StringId& name ) const
{
if( name == "_"_sid )
return nullptr;
|
| ︙ | ︙ | |||
49 50 51 52 53 54 55 |
setupVars();
m_pVars->emplace( name, forward< T >( val ) );
return true;
}
void addComplexity( uint32_t n ) { m_complexity += n; }
| < < < < < < < < < < < < < < < < | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
setupVars();
m_pVars->emplace( name, forward< T >( val ) );
return true;
}
void addComplexity( uint32_t n ) { m_complexity += n; }
private:
void setupVars();
ptr< unordered_map< StringId, any > > m_pVars;
uint32_t m_complexity = 0; // Each matched structural element of the pattern (vector) adds 1,
// each matched literal element of the pattern adds 2
};
|
| ︙ | ︙ |
Changes to bs/eir/value.cpp.
| ︙ | ︙ | |||
104 105 106 107 108 109 110 |
}
Term ValueToEIR( const ValuePattern& v )
{
return VEC( TSID( value ), v.sort(), v.type(), v.val(), static_cast< LocationId >( v.locationId() ) );
}
| | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
}
Term ValueToEIR( const ValuePattern& v )
{
return VEC( TSID( value ), v.sort(), v.type(), v.val(), static_cast< LocationId >( v.locationId() ) );
}
optional< ValuePattern > ValuePatternFromEIR( const Term& t )
{
auto result = Decompose( t,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
|
| ︙ | ︙ |
Changes to bs/eir/value.h.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
extern const Term& TypeType();
extern Term ValueToEIR( const Value& v );
extern optional< Value > ValueFromEIR( const Term& t );
extern Term ValueToEIR( const ValuePattern& v );
| | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
extern const Term& TypeType();
extern Term ValueToEIR( const Value& v );
extern optional< Value > ValueFromEIR( const Term& t );
extern Term ValueToEIR( const ValuePattern& v );
extern optional< ValuePattern > ValuePatternFromEIR( const Term& t );
class Value
{
public:
Value() : m_locationId( ~0 ) {}
template< typename T, typename VL >
|
| ︙ | ︙ |
Changes to bs/sema/env.cpp.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
} );
++m_valueStoreVersion;
}
Env::Status Env::retrieveValue( const Term& id, const Term& contextId, Term& result )
{
| | > | | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
} );
++m_valueStoreVersion;
}
Env::Status Env::retrieveValue( const Term& id, const Term& contextId, Term& result )
{
MatchScore bestScore;
ptr< ValueProvider > bestProvider;
bool ambiguous = false;
auto pat = VEC( id, contextId );
for( auto&& [s, provider] : Match( pat, m_valueStore ) )
{
auto score = s.score();
if( !bestProvider || score > bestScore )
{
bestScore = score;
bestProvider = provider;
ambiguous = false;
continue;
}
if( score < bestScore )
continue;
ambiguous = true;
}
if( !bestProvider )
return Status::NoMatch;
|
| ︙ | ︙ |
Changes to bs/sema/invocation.cpp.
1 2 3 4 5 6 7 8 9 10 |
#include "sema.h"
#include "builtins/builtins.h"
#include "execute/execute.h"
namespace goose::sema
{
ptr< InvocationRule > GetInvocationRule( const Env& e, const Value& callee )
{
const auto& rules = e.invocationRuleSet()->rules();
| | > | | | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#include "sema.h"
#include "builtins/builtins.h"
#include "execute/execute.h"
namespace goose::sema
{
ptr< InvocationRule > GetInvocationRule( const Env& e, const Value& callee )
{
const auto& rules = e.invocationRuleSet()->rules();
MatchScore bestScore;
ptr< InvocationRule > pBestRule;
bool ambiguous = false;
auto calleeTerm = ValueToEIR( callee );
for( auto&& [s, rule] : Match( calleeTerm, rules ) )
{
auto score = s.score();
if( !pBestRule || score > bestScore )
{
bestScore = score;
pBestRule = rule;
ambiguous = false;
continue;
}
if( score < bestScore )
continue;
ambiguous = true;
}
if( ambiguous )
G_VAL_ERROR( callee, "ambiguous invocation rule" );
return pBestRule;
}
bool CanBeInvoked( const Context& c, const Value& callee )
{
auto pIR = GetInvocationRule( *c.env(), callee );
|
| ︙ | ︙ |
Changes to bs/sema/tc-context.h.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
uint32_t RHSNamespaceIndex() const { return m_currentRHSNamespaceIndex; }
void setLHSNamespaceIndex( uint32_t index ) { m_currentLHSNamespaceIndex = index; }
void setRHSNamespaceIndex( uint32_t index ) { m_currentRHSNamespaceIndex = index; }
uint32_t newNamespaceIndex() { return m_nextNamespaceIndex++; }
| | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
uint32_t RHSNamespaceIndex() const { return m_currentRHSNamespaceIndex; }
void setLHSNamespaceIndex( uint32_t index ) { m_currentLHSNamespaceIndex = index; }
void setRHSNamespaceIndex( uint32_t index ) { m_currentRHSNamespaceIndex = index; }
uint32_t newNamespaceIndex() { return m_nextNamespaceIndex++; }
// By default, any encountered hole will be considered as required, ie
// they will count towards numUnknownValues() if we can't solve them.
// This function allows to temporarily disable this, so that any hole
// encountered from that point on will not count towards unresolved holes,
// unless they also appear in a section where holes are required.
void setValueResolutionRequired( bool required )
{
m_valuesAreRequired = required;
|
| ︙ | ︙ |
Changes to bs/sema/tc-ruleset.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "sema.h"
using namespace goose;
using namespace goose::sema;
TypeCheckingRuleSet::TypeCheckingRuleSet()
{
SetupBasicUnificationRules( *this );
SetupPostProcUnificationRules( *this );
SetupHoleUnificationRules( *this );
SetupQuoteUnificationRules( *this );
}
| > > > > > | | | | | | < < < < < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include "sema.h"
using namespace goose;
using namespace goose::sema;
TypeCheckingRuleSet::TypeCheckingRuleSet()
{
SetupBasicUnificationRules( *this );
SetupPostProcUnificationRules( *this );
SetupHoleUnificationRules( *this );
SetupQuoteUnificationRules( *this );
}
void TypeCheckingRuleSet::addTypeCheckingRule( TCRuleInfo&& infos, const Term& pat1, const Term& pat2, BinaryFunc f )
{
m_typeCheckingRules = Merge( m_typeCheckingRules, VEC( pat1, pat2 ), [&]( auto&& ){ return BinaryRule{ f, infos }; } );
}
void TypeCheckingRuleSet::addUnificationRule( TCRuleInfo&& infos, const Term& pat, BinaryFunc f )
{
m_uniRules = Merge( m_uniRules, VEC( pat, pat ), [&]( auto&& ){ return BinaryRule{ f, infos }; } );
}
TCGen FlippedContextAdapter( const Term& lhs, const Term& rhs, TypeCheckingContext tcc, TypeCheckingRuleSet::BinaryFunc f )
{
for( auto&& [e,tcc] : f( rhs, lhs, tcc.flip() ) )
co_yield { move( e ), tcc.flip() };
}
void TypeCheckingRuleSet::addUnificationRule( TCRuleInfo&& infos, const Term& pat1, const Term& pat2, BinaryFunc f )
{
m_uniRules = Merge( m_uniRules, VEC( pat1, pat2 ), [&]( auto&& ){ return BinaryRule{ f, infos }; } );
m_uniRules = Merge( m_uniRules, VEC( pat2, pat1 ),
[&]( auto&& ){ return BinaryRule{ BinaryFunc( [&,f]( auto&& lhs, auto&& rhs, auto&& c ) -> TCGen
{
return FlippedContextAdapter( lhs, rhs, c, f );
} ), infos }; }
);
}
void TypeCheckingRuleSet::addHalfUnificationRule( TCRuleInfo&& infos, const Term& pat, UnaryFunc f )
{
m_halfUniRules = Merge( m_halfUniRules, pat, [&]( auto&& ){ return UnaryRule{ f, infos }; } );
}
|
Changes to bs/sema/tc-ruleset.h.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
#define TCRINFOS TCRuleInfo{}
#endif
class TypeCheckingRuleSet
{
public:
| | | | | | | | | | | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#define TCRINFOS TCRuleInfo{}
#endif
class TypeCheckingRuleSet
{
public:
using BinaryFunc = function< TCGen ( const Term& lhs, const Term& rhs, const TypeCheckingContext& ) >;
using UnaryFunc = function< optional< Term > ( const Term& lhs, TypeCheckingContext& ) >;
struct BinaryRule
{
BinaryFunc func;
TCRuleInfo infos;
};
struct UnaryRule
{
UnaryFunc func;
TCRuleInfo infos;
};
TypeCheckingRuleSet();
void addTypeCheckingRule( TCRuleInfo&& infos, const Term& pat1, const Term& pat2, BinaryFunc f );
void addUnificationRule( TCRuleInfo&& infos, const Term& pat, BinaryFunc f );
void addUnificationRule( TCRuleInfo&& infos, const Term& pat1, const Term& pat2, BinaryFunc f );
void addHalfUnificationRule( TCRuleInfo&& infos, const Term& pat, UnaryFunc f );
const auto& typeCheckingRules() const { return m_typeCheckingRules; }
const auto& uniRules() const { return m_uniRules; }
const auto& halfUniRules() const { return m_halfUniRules; }
private:
Trie< BinaryRule > m_typeCheckingRules;
Trie< BinaryRule > m_uniRules;
Trie< UnaryRule > m_halfUniRules;
};
}
#endif
|
Changes to bs/sema/tctrie-typecheck.inl.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 |
else
{
const auto& vt = vgen();
for( auto&& rt : Enumerate( rptNode.m_repetition ) )
{
auto newC = tcc;
| | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
else
{
const auto& vt = vgen();
for( auto&& rt : Enumerate( rptNode.m_repetition ) )
{
auto newC = tcc;
newC.addComplexity( GetComplexity( rt ) );
auto localRhsVec = lhsVec;
localRhsVec.setRepetitionTerm( rt );
for( auto&& [s,tcc] : sema::TypeCheck( rt, vt, newC ) )
co_yield TypeCheckRepetition( vgen, localRhsVec, Vector::MakeAppend( solutionVec, move( s ) ), rptNode, tcc );
}
}
}
template< typename U > template< typename T > Generator< tuple< Vector, Vector, const T&, TypeCheckingContext, VecGenerator > >
TCTrie< U >::TypeCheck( VecGenerator vgen, const Vector& lhsVec, const Vector& solutionVec, const branch_t& branch, const TypeCheckingContext& tcc )
{
if( branch.index() == 0 )
{
const auto& vt = vgen();
for( auto&& [t, payload] : Enumerate( get< 0 >( branch )->m_trie ) )
{
auto newC = tcc;
newC.addComplexity( GetComplexity( t ) );
auto lvec = Vector::MakeAppend( lhsVec, t );
for( auto&& [s, tcc] : sema::TypeCheck( t, vt, newC ) )
co_yield TypeCheck< T >( vgen, lvec, Vector::MakeAppend( solutionVec, move( s ) ), payload, tcc );
}
}
else
|
| ︙ | ︙ |
Changes to bs/sema/template.cpp.
1 2 3 4 5 6 7 8 |
#include "sema.h"
namespace goose::sema
{
ptr< TemplateRule > GetTemplateRuleSet( const Context& c, const Term& tpl )
{
const auto& rules = c.env()->templateRuleSet()->rules();
| | > | | | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include "sema.h"
namespace goose::sema
{
ptr< TemplateRule > GetTemplateRuleSet( const Context& c, const Term& tpl )
{
const auto& rules = c.env()->templateRuleSet()->rules();
MatchScore bestScore;
ptr< TemplateRule > pBestRule;
bool ambiguous = false;
for( auto&& [s, rule] : Match( tpl, rules ) )
{
auto score = s.score();
if( !pBestRule || score > bestScore )
{
bestScore = score;
pBestRule = rule;
ambiguous = false;
continue;
}
if( score < bestScore )
continue;
ambiguous = true;
}
if( ambiguous )
G_ERROR( "ambiguous template rule" );
return pBestRule;
}
optional< Term > BuildTemplateSignature( const Context& c, const Term& tpl )
{
const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
|
| ︙ | ︙ |
Changes to bs/sema/tests/meson.build.
1 2 3 4 5 6 7 8 9 10 11 12 |
tests = [
'unify-holes',
'tctrie-merge',
'tctrie-typecheck'
]
foreach t : tests
exe = executable( 'sema-' + t, t + '.cpp',
link_with:
[
goose_util,
goose_eir,
| | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
tests = [
'unify-holes',
'tctrie-merge',
'tctrie-typecheck'
]
foreach t : tests
exe = executable( 'sema-' + t, t + '.cpp',
link_with:
[
goose_util,
goose_eir,
goose_sema,
goose_diagnostics
],
include_directories: bsinc,
dependencies: [catch2_dep, fmt_dep, llvm_dep]
)
test( 'sema-' + t, exe )
endforeach
|
Changes to bs/sema/tests/tctrie-merge.cpp.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 |
auto vec8 = Vector::Make( HOLE( "a"_sid ), HOLE( "c"_sid ) );
auto vec9 = Vector::Make( TERM( vec5 ), TERM( vec1 ) );
auto vec10 = Vector::Make( HOLE( "x"_sid ), TERM( vec4 ), HOLE( "z"_sid ), HOLE( "z"_sid ) );
auto vec11 = Vector::Make( TERM( vec5 ), HOLE( "y"_sid ), HOLE( "y"_sid ), TERM( vec5 ) );
auto vec12 = Vector::Make( VEC( HOLE( "a"_sid ), TSTR( "foo" ) ), HOLE( "a"_sid ) );
| | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
auto vec8 = Vector::Make( HOLE( "a"_sid ), HOLE( "c"_sid ) );
auto vec9 = Vector::Make( TERM( vec5 ), TERM( vec1 ) );
auto vec10 = Vector::Make( HOLE( "x"_sid ), TERM( vec4 ), HOLE( "z"_sid ), HOLE( "z"_sid ) );
auto vec11 = Vector::Make( TERM( vec5 ), HOLE( "y"_sid ), HOLE( "y"_sid ), TERM( vec5 ) );
auto vec12 = Vector::Make( VEC( HOLE( "a"_sid ), TSTR( "foo" ) ), HOLE( "a"_sid ) );
auto vec13 = Vector::Make( HOLE( "b"_sid ), HOLE( "b"_sid ) );
auto trie = TCTrie< string >().merge( *vec1, []( auto&& ){ return "vec1"s; } );
trie = trie->merge( *vec2, []( auto&& ){ return "vec2"s; } );
trie = trie->merge( *vec3, []( auto&& ){ return "vec3"s; } );
trie = trie->merge( *vec4, []( auto&& ){ return "vec4"s; } );
trie = trie->merge( *vec5, []( auto&& ){ return "vec5"s; } );
trie = trie->merge( *vec6, []( auto&& ){ return "vec6"s; } );
|
| ︙ | ︙ |
Changes to bs/sema/tests/tctrie-typecheck.cpp.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 |
auto vec3 = Vector::Make( TSTR( "meh" ), TSTR( "meh" ) );
auto vec4 = Vector::Make( HOLE( "a"_sid ), TSTR( "bar" ) );
auto vec5 = Vector::Make( TSTR( "foo" ), HOLE( "b"_sid ) );
auto vec9 = Vector::Make( TERM( vec5 ), TERM( vec1 ) );
| | | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
auto vec3 = Vector::Make( TSTR( "meh" ), TSTR( "meh" ) );
auto vec4 = Vector::Make( HOLE( "a"_sid ), TSTR( "bar" ) );
auto vec5 = Vector::Make( TSTR( "foo" ), HOLE( "b"_sid ) );
auto vec9 = Vector::Make( TERM( vec5 ), TERM( vec1 ) );
auto vec10 = Vector::Make( HOLE( "x"_sid ), TERM( vec4 ), HOLE( "z"_sid ), HOLE( "z"_sid ) );
auto vec11 = Vector::Make( TERM( vec5 ), HOLE( "y"_sid ), HOLE( "y"_sid ), TERM( vec5 ) );
auto vec12 = Vector::Make( VEC( HOLE( "a"_sid ), TSTR( "foo" ) ), HOLE( "a"_sid ) );
auto vec13 = Vector::Make( HOLE( "b"_sid ), HOLE( "b"_sid ) );
auto trie = TCTrie< string >().merge( *vec2, []( auto&& ){ return "vec2"s; } );
trie = trie->merge( *vec4, []( auto&& ){ return "vec4"s; } );
trie = trie->merge( *vec10, []( auto&& ){ return "vec10"s; } );
trie = trie->merge( *vec12, []( auto&& ){ return "vec12"s; } );
THEN( "We obtain the expected solutions" )
|
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
REQUIRE( sols5[1] == make_tuple( VEC( TSTR( "foo" ), TSTR( "bar" ) ), "vec4"s, TypeCheckingScore( 2, 2 ) ) );
REQUIRE( sols9.size() == 1 );
REQUIRE( sols9[0] == make_tuple(
VEC(
VEC( TSTR( "foo" ), TSTR( "bar" ) ),
VEC( TSTR( "foo" ), TSTR( "bar" ) )
| | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
REQUIRE( sols5[1] == make_tuple( VEC( TSTR( "foo" ), TSTR( "bar" ) ), "vec4"s, TypeCheckingScore( 2, 2 ) ) );
REQUIRE( sols9.size() == 1 );
REQUIRE( sols9[0] == make_tuple(
VEC(
VEC( TSTR( "foo" ), TSTR( "bar" ) ),
VEC( TSTR( "foo" ), TSTR( "bar" ) )
), "vec2"s, TypeCheckingScore( 2, 2 ) )
);
REQUIRE( sols11.size() == 1 );
REQUIRE( sols11[0] == make_tuple(
VEC(
VEC( TSTR( "foo" ), TSTR( "bar" ) ),
VEC( TSTR( "foo" ), TSTR( "bar" ) ),
VEC( TSTR( "foo" ), TSTR( "bar" ) ),
VEC( TSTR( "foo" ), TSTR( "bar" ) )
), "vec10"s, TypeCheckingScore( 3, 5 ) )
);
REQUIRE( sols13.size() == 1 );
REQUIRE( sols13[0] == make_tuple( VEC( TSTR( "bar" ), TSTR( "bar" ) ), "vec4"s, TypeCheckingScore( 2, 2 ) ) );
}
}
}
|
Changes to bs/sema/tests/unify-holes.cpp.
| ︙ | ︙ | |||
64 65 66 67 68 69 70 |
auto expr6 = VEC( HOLE( "a"_sid ), HOLE( "a"_sid ) );
auto expr7 = VEC( TSTR( "foo" ), HOLE( "b"_sid ) );
auto expr8 = VEC( HOLE( "a"_sid ), HOLE( "a"_sid ) );
auto expr9 = VEC( expr5, expr1 );
| | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
auto expr6 = VEC( HOLE( "a"_sid ), HOLE( "a"_sid ) );
auto expr7 = VEC( TSTR( "foo" ), HOLE( "b"_sid ) );
auto expr8 = VEC( HOLE( "a"_sid ), HOLE( "a"_sid ) );
auto expr9 = VEC( expr5, expr1 );
auto expr10 = VEC( HOLE( "x"_sid ), expr4, HOLE( "z"_sid ), HOLE( "z"_sid ) );
auto expr11 = VEC( expr5, HOLE( "y"_sid ), HOLE( "y"_sid ), expr5 );
auto expr12 = VEC( VEC( HOLE( "a"_sid ), TSTR( "foo" ) ), HOLE( "a"_sid ) );
auto expr13 = VEC( HOLE( "b"_sid ), HOLE( "b"_sid ) );
THEN( "Unifications yields the expected solutions" )
{
CheckForUniqueSolution( expr0, expr1, VEC( TSTR( "foo" ), TSTR( "bar" ) ), { 1, 1 } );
|
| ︙ | ︙ |
Changes to bs/sema/typecheck.cpp.
1 2 3 4 5 6 7 8 |
#include "sema.h"
namespace goose::sema
{
template< typename F >
TypeCheckingSolution FindBestTyping( const Term& lhs, const Term& rhs, const Context& context, F&& typeChecker )
{
optional< TypeCheckingContext > bestTCC;
| | | | | | | | > | | | < | | | | > | | | < | | | > | | | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
#include "sema.h"
namespace goose::sema
{
template< typename F >
TypeCheckingSolution FindBestTyping( const Term& lhs, const Term& rhs, const Context& context, F&& typeChecker )
{
optional< TypeCheckingContext > bestTCC;
optional< Term > bestScore;
bool ambiguous = false;
TypeCheckingContext tcc( context );
tcc.setComplexity( GetComplexity( lhs ) );
for( auto&& [s, tcc] : typeChecker( lhs, rhs, tcc ) )
{
if( tcc.numUnknownValues() )
continue;
if( bestTCC && tcc.score() < bestTCC->score() )
continue;
auto pps = Postprocess( s, tcc );
if( !pps )
continue;
if( bestTCC && tcc.score() == bestTCC->score() )
{
ambiguous = true;
continue;
}
bestTCC = tcc;
bestScore = move( *pps );
ambiguous = false;
}
if( ambiguous )
return AmbiguousTypeCheck{};
if( !bestScore )
return {};
return make_pair( move( *bestScore ), move( *bestTCC ) );
}
TypeCheckingSolution FindBestTyping( const Term& lhs, const Term& rhs, const Context& context )
{
return FindBestTyping( lhs, rhs, context,
[]( auto&& lhs, auto&& rhs, auto&& tcc ) { return TypeCheck( lhs, rhs, tcc ); } );
}
TCGen TypeCheck( const Term& lhs, const Term& rhs, const TypeCheckingContext& context )
{
const auto& rules = context.rules()->typeCheckingRules();
MatchScore bestScore;
optional< TypeCheckingRuleSet::BinaryRule > bestRule;
bool ambiguous = false;
auto expr = VEC( lhs, rhs );
for( auto&& [s, rule] : Match( expr, rules ) )
{
auto score = s.score();
if( !bestRule || score > bestScore )
{
bestScore = score;
bestRule = rule;
ambiguous = false;
continue;
}
if( score < bestScore )
continue;
ambiguous = true;
}
if( ambiguous )
G_VAL_ERROR( *ValuePatternFromEIR( rhs ), "ambiguous type checking rule" );
if( !bestRule )
co_return;
#ifdef TCRULES_DEBUG
cout << "calling typechecking rule " << bestRule->infos.pFilename << ':' << bestRule->infos.line << endl;
cout << " lhs " << lhs << endl;
cout << " rhs " << rhs << endl;
#endif
co_yield bestRule->func( lhs, rhs, context );
}
TCGen Unify( const Term& lhs, const Term& rhs, const TypeCheckingContext& context )
{
const auto& rules = context.rules()->uniRules();
MatchScore bestScore;
optional< TypeCheckingRuleSet::BinaryRule > bestRule;
bool ambiguous = false;
auto expr = VEC( lhs, rhs );
for( auto&& [s, rule] : Match( expr, rules ) )
{
auto score = s.score();
if( !bestRule || score > bestScore )
{
bestScore = score;
bestRule = rule;
ambiguous = false;
continue;
}
if( score < bestScore )
continue;
ambiguous = true;
}
if( ambiguous )
G_ERROR( "ambiguous unification rule" );
if( !bestRule )
co_return;
co_yield bestRule->func( lhs, rhs, context );
}
optional< Term > HalfUnify( const Term& lhs, TypeCheckingContext& context )
{
const auto& rules = context.rules()->halfUniRules();
MatchScore bestScore;
optional< TypeCheckingRuleSet::UnaryRule > bestRule;
bool ambiguous = false;
for( auto&& [s, rule] : Match( lhs, rules ) )
{
auto score = s.score();
if( !bestRule || score > bestScore )
{
bestScore = score;
bestRule = rule;
ambiguous = false;
continue;
}
if( score < bestScore )
continue;
ambiguous = true;
}
if( ambiguous )
G_ERROR( "ambiguous half-unification rule" );
if( !bestRule )
return nullopt;
return bestRule->func( lhs, context );
}
|
| ︙ | ︙ |
Changes to bs/verify/condition.cpp.
| ︙ | ︙ | |||
104 105 106 107 108 109 110 |
for( auto&& unsatExpr : unsatCore )
{
auto it = find_if( m_idAndLocs.begin(), m_idAndLocs.end(),
[&]( auto&&x ) { return x.first == unsatExpr.id(); } );
if( it == m_idAndLocs.end() )
| | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
for( auto&& unsatExpr : unsatCore )
{
auto it = find_if( m_idAndLocs.begin(), m_idAndLocs.end(),
[&]( auto&&x ) { return x.first == unsatExpr.id(); } );
if( it == m_idAndLocs.end() )
G_ERROR( "unknown id in unsat core" );
errorLocations.push_back( it->second );
}
// Sort the unsatisfiable conditions by location ids, because z3 doesn't
// provide them in a deterministic order.
sort( errorLocations.begin(), errorLocations.end() );
|
| ︙ | ︙ |