mirror of https://github.com/AMT-Cheif/drift.git
New type resolver: Start propagating known types
This commit is contained in:
parent
373ad320c4
commit
c95a5f0aad
|
@ -8,7 +8,11 @@
|
|||
```
|
||||
selectVariable(:variable AS TEXT): SELECT :variable;
|
||||
```
|
||||
- Support for triggers! You can declare them in a `.moor` file and
|
||||
- Support for triggers and indices! You can declare them in a `.moor` file with a regular `CREATE TRIGGER`
|
||||
or `CREATE INDEX` statement. Both triggers and indices will be created in the default `onCreate` function.
|
||||
To create them in `onUpgrade`, use the new `createIndex` and `createTrigger` functions on a `Migrator`.
|
||||
- Support for moor-file queries that run on initialization ([#280](https://github.com/simolus3/moor/issues/280))
|
||||
Declare them like this `@create: INSERT INTO users VALUES ('default', 'user')`
|
||||
|
||||
## 2.2.0
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ class HaveSameType extends TypeRelationship {
|
|||
final Typeable second;
|
||||
|
||||
HaveSameType(this.first, this.second);
|
||||
|
||||
Typeable getOther(Typeable t) {
|
||||
assert(t == first || t == second);
|
||||
return t == first ? second : first;
|
||||
}
|
||||
}
|
||||
|
||||
/// Dependency declaring that, if no better option is found, [target] should
|
||||
|
|
|
@ -2,6 +2,11 @@ part of '../types.dart';
|
|||
|
||||
class TypeGraph {
|
||||
final Map<Typeable, ResolvedType> _knownTypes = {};
|
||||
final Map<Typeable, bool> _knownNullability = {};
|
||||
|
||||
final List<TypeRelationship> _relationships = [];
|
||||
|
||||
final Map<Typeable, List<TypeRelationship>> _edges = {};
|
||||
|
||||
TypeGraph();
|
||||
|
||||
|
@ -11,6 +16,80 @@ class TypeGraph {
|
|||
|
||||
void operator []=(Typeable t, ResolvedType type) {
|
||||
_knownTypes[t] = type;
|
||||
|
||||
if (type.nullable != null) {
|
||||
// nullability is known
|
||||
_knownNullability[t] = type.nullable;
|
||||
}
|
||||
}
|
||||
|
||||
bool knowsType(Typeable t) => _knownTypes.containsKey(t);
|
||||
|
||||
void addRelation(TypeRelationship relation) {
|
||||
_relationships.add(relation);
|
||||
}
|
||||
|
||||
void performResolve() {
|
||||
_indexRelationships();
|
||||
|
||||
final queue = List.of(_knownTypes.keys);
|
||||
while (queue.isNotEmpty) {
|
||||
_propagateTypeInfo(queue, queue.removeLast());
|
||||
}
|
||||
}
|
||||
|
||||
void _propagateTypeInfo(List<Typeable> resolved, Typeable t) {
|
||||
if (!_edges.containsKey(t)) return;
|
||||
|
||||
for (final edge in _edges[t]) {
|
||||
if (edge is CopyTypeFrom) {
|
||||
_copyType(resolved, edge.other, edge.target);
|
||||
} else if (edge is HaveSameType) {
|
||||
_copyType(resolved, t, edge.getOther(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _copyType(List<Typeable> resolved, Typeable from, Typeable to) {
|
||||
// if the target hasn't been resolved yet, copy the current type and
|
||||
// visit the target later
|
||||
if (!knowsType(to)) {
|
||||
this[to] = this[from];
|
||||
resolved.add(to);
|
||||
}
|
||||
}
|
||||
|
||||
void _indexRelationships() {
|
||||
_edges.clear();
|
||||
|
||||
void put(Typeable t, TypeRelationship r) {
|
||||
_edges.putIfAbsent(t, () => []).add(r);
|
||||
}
|
||||
|
||||
void putAll(Iterable<Typeable> t, TypeRelationship r) {
|
||||
for (final element in t) {
|
||||
put(element, r);
|
||||
}
|
||||
}
|
||||
|
||||
for (final relation in _relationships) {
|
||||
if (relation is NullableIfSomeOtherIs) {
|
||||
putAll(relation.other, relation);
|
||||
} else if (relation is CopyTypeFrom) {
|
||||
put(relation.other, relation);
|
||||
} else if (relation is CopyEncapsulating) {
|
||||
putAll(relation.from, relation);
|
||||
} else if (relation is HaveSameType) {
|
||||
put(relation.first, relation);
|
||||
put(relation.second, relation);
|
||||
} else if (relation is DefaultType) {
|
||||
put(relation.target, relation);
|
||||
} else if (relation is CopyAndCast) {
|
||||
put(relation.other, relation);
|
||||
} else {
|
||||
throw AssertionError('Unknown type relation: $relation');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ class TypeResolver extends RecursiveVisitor<TypeExpectation, void> {
|
|||
|
||||
TypeResolver(this.session);
|
||||
|
||||
void start(AstNode root) {
|
||||
void run(AstNode root) {
|
||||
visit(root, const NoTypeExpectation());
|
||||
session.finish();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -33,13 +33,17 @@ class TypeInferenceSession {
|
|||
return graph[t];
|
||||
}
|
||||
|
||||
void addRelationship(TypeRelationship relationship) {}
|
||||
void addRelationship(TypeRelationship relationship) {
|
||||
graph.addRelation(relationship);
|
||||
}
|
||||
|
||||
void expectIsPossible(ResolvedType r, TypeExpectation expectation) {}
|
||||
|
||||
void hintNullability(Typeable t, bool nullable) {
|
||||
assert(nullable != null);
|
||||
}
|
||||
|
||||
void finish() {}
|
||||
}
|
||||
|
||||
/// Keeps track of resolved variable types so that they can be re-used.
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import 'package:sqlparser/sqlparser.dart';
|
||||
import 'package:sqlparser/src/analysis/types2/types.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
class _FakeTypeable implements Typeable {}
|
||||
|
||||
void main() {
|
||||
test('copies types for a CopyTypeFrom relation', () {
|
||||
final first = _FakeTypeable();
|
||||
final second = _FakeTypeable();
|
||||
|
||||
final graph = TypeGraph();
|
||||
graph[first] = const ResolvedType.bool();
|
||||
graph.addRelation(CopyTypeFrom(second, first));
|
||||
graph.performResolve();
|
||||
|
||||
expect(graph[second], const ResolvedType.bool());
|
||||
});
|
||||
}
|
|
@ -11,7 +11,7 @@ void main() {
|
|||
|
||||
TypeResolver _obtainResolver(String sql) {
|
||||
final context = engine.analyze(sql);
|
||||
return TypeResolver(TypeInferenceSession(context))..start(context.root);
|
||||
return TypeResolver(TypeInferenceSession(context))..run(context.root);
|
||||
}
|
||||
|
||||
ResolvedType _resolveFirstVariable(String sql) {
|
||||
|
|
Loading…
Reference in New Issue