Skip to content

Commit

Permalink
resolve: implement VariableDependencyCollector
Browse files Browse the repository at this point in the history
  • Loading branch information
mio-19 committed Dec 24, 2024
1 parent 6473239 commit e5bd164
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.resolve.error;

import org.aya.pretty.doc.Doc;
import org.aya.util.prettier.PrettierOptions;
import org.aya.util.reporter.Problem;
import org.aya.syntax.ref.GeneralizedVar;
import org.aya.util.error.SourcePos;
import org.jetbrains.annotations.NotNull;

public record CyclicDependencyError(
@NotNull SourcePos sourcePos,
@NotNull GeneralizedVar var
) implements Problem {
@Override public @NotNull Severity level() { return Severity.ERROR; }
@Override public @NotNull Stage stage() { return Stage.RESOLVE; }
@Override public @NotNull Doc describe(@NotNull PrettierOptions options) {
return Doc.sep(
Doc.plain("Cyclic dependency detected in variable declaration:"),
Doc.plain(var.name())
);
}
}
35 changes: 8 additions & 27 deletions base/src/main/java/org/aya/resolve/visitor/ExprResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ public record ExprResolver(
boolean allowGeneralizing,
@NotNull MutableMap<GeneralizedVar, Expr.Param> allowedGeneralizes,
@NotNull MutableList<TyckOrder> reference,
@NotNull MutableStack<Where> where
@NotNull MutableStack<Where> where,
@NotNull VariableDependencyCollector collector
) implements PosedUnaryOperator<Expr> {
public record LiterateResolved(
ImmutableSeq<Expr.Param> params,
Expand All @@ -69,23 +70,24 @@ public static LiterateResolved resolveLax(@NotNull ModuleContext context, @NotNu
}

public ExprResolver(@NotNull Context ctx, boolean allowGeneralizing) {
this(ctx, allowGeneralizing, MutableLinkedHashMap.of(), MutableList.create(), MutableStack.create());
this(ctx, allowGeneralizing, MutableLinkedHashMap.of(), MutableList.create(), MutableStack.create(),
new VariableDependencyCollector(ctx.reporter()));
}

public void resetRefs() { reference.clear(); }
public void enter(Where loc) { where.push(loc); }
public void exit() { where.pop(); }

public @NotNull ExprResolver enter(Context ctx) {
return ctx == ctx() ? this : new ExprResolver(ctx, allowGeneralizing, allowedGeneralizes, reference, where);
return ctx == ctx() ? this : new ExprResolver(ctx, allowGeneralizing, allowedGeneralizes, reference, where, collector);
}

/**
* The intended usage is to create an {@link ExprResolver}
* that resolves the body/bodies of something.
*/
public @NotNull ExprResolver deriveRestrictive() {
return new ExprResolver(ctx, false, allowedGeneralizes, reference, where);
return new ExprResolver(ctx, false, allowedGeneralizes, reference, where, collector);
}

public @NotNull Expr pre(@NotNull Expr expr) {
Expand Down Expand Up @@ -258,7 +260,7 @@ private void addReference(@NotNull DefVar<?, ?> defVar) {
private void introduceDependencies(@NotNull GeneralizedVar var) {
if (allowedGeneralizes.containsKey(var)) return;

var dependencies = getDependencies(var);
var dependencies = collector.getDependencies(var);
for (var dep : dependencies) {
introduceDependencies(dep);
}
Expand All @@ -270,27 +272,6 @@ private void introduceDependencies(@NotNull GeneralizedVar var) {
addReference(owner);
}

private @NotNull ImmutableSeq<GeneralizedVar> getDependencies(@NotNull GeneralizedVar var) {
var collector = new GeneralizedVarCollector();
var.owner.type.descent(collector);
return collector.getCollected();
}

private static class GeneralizedVarCollector implements PosedUnaryOperator<Expr> {
private final MutableList<GeneralizedVar> collected = MutableList.create();

@Override
public @NotNull Expr apply(@NotNull SourcePos pos, @NotNull Expr expr) {
if (expr instanceof Expr.Ref ref && ref.var() instanceof GeneralizedVar gvar) {
collected.append(gvar);
}
return expr.descent(this);
}

public ImmutableSeq<GeneralizedVar> getCollected() {
return collected.toImmutableSeq();
}
}
public @NotNull AnyVar resolve(@NotNull QualifiedID name) {
var result = ctx.get(name);
if (result instanceof GeneralizedVar gvar) {
Expand All @@ -305,7 +286,7 @@ public ImmutableSeq<GeneralizedVar> getCollected() {
public @NotNull ExprResolver member(@NotNull TyckUnit decl, Where initial) {
var resolver = new ExprResolver(ctx, false, allowedGeneralizes,
MutableList.of(new TyckOrder.Head(decl)),
MutableStack.create());
MutableStack.create(), collector);
resolver.enter(initial);
return resolver;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.resolve.visitor;

import kala.collection.immutable.ImmutableSeq;
import kala.collection.mutable.MutableList;
import kala.collection.mutable.MutableSet;
import org.aya.util.error.PosedUnaryOperator;
import org.aya.resolve.context.Context;
import org.aya.resolve.error.CyclicDependencyError;
import org.aya.syntax.concrete.Expr;
import org.aya.syntax.ref.GeneralizedVar;
import org.aya.util.error.SourcePos;
import org.aya.util.reporter.Reporter;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;

public final class VariableDependencyCollector {
private final Map<GeneralizedVar, ImmutableSeq<GeneralizedVar>> dependencies = new HashMap<>();
private final Reporter reporter;
private final MutableSet<GeneralizedVar> visiting = MutableSet.create();

public VariableDependencyCollector(Reporter reporter) {
this.reporter = reporter;
}

public void registerVariable(GeneralizedVar var) {
if (dependencies.containsKey(var)) return;

// If var is already being visited, we found a cycle.
if (!visiting.add(var)) {
reporter.report(new CyclicDependencyError(var.sourcePos(), var));
throw new Context.ResolvingInterruptedException();
}

var deps = collectReferences(var);
dependencies.put(var, deps);
visiting.remove(var);

// Recursively register dependencies
for (var dep : deps) registerVariable(dep);
}

public ImmutableSeq<GeneralizedVar> getDependencies(GeneralizedVar var) {
return dependencies.getOrDefault(var, ImmutableSeq.empty());
}

private ImmutableSeq<GeneralizedVar> collectReferences(GeneralizedVar var) {
var type = var.owner.type;
var collector = new StaticGeneralizedVarCollector();
type.descent(collector);
return collector.getCollected();
}

private static class StaticGeneralizedVarCollector implements PosedUnaryOperator<Expr> {
private final MutableList<GeneralizedVar> collected = MutableList.create();

@Override
public @NotNull Expr apply(@NotNull SourcePos pos, @NotNull Expr expr) {
if (expr instanceof Expr.Ref ref && ref.var() instanceof GeneralizedVar gvar) {
collected.append(gvar);
}
return expr.descent(this);
}

public ImmutableSeq<GeneralizedVar> getCollected() {
return collected.toImmutableSeq();
}
}
}

0 comments on commit e5bd164

Please sign in to comment.