Skip to content

Commit

Permalink
TyTy: Variance analysis module
Browse files Browse the repository at this point in the history
gcc/rust/ChangeLog:

	* Make-lang.in: Add new .cc file.
	* rust-session-manager.cc (Session::compile_crate): Run
	analysis.
	* typecheck/rust-tyty-variance-analysis-private.h: New file.
	* typecheck/rust-tyty-variance-analysis.cc: New file.
	* typecheck/rust-tyty-variance-analysis.h: New file.
	* typecheck/rust-typecheck-context.cc
	(TypeCheckContext::get_variance_analysis_ctx):
	Variance analysis context.
	* typecheck/rust-hir-type-check.h (TypeCheckItem::visit):
	Variance analysis context.

Signed-off-by: Jakub Dupak <[email protected]>
  • Loading branch information
jdupak authored and CohenArthur committed Mar 21, 2024
1 parent fdba6c5 commit 4a54a8b
Show file tree
Hide file tree
Showing 7 changed files with 975 additions and 0 deletions.
1 change: 1 addition & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ GRS_OBJS = \
rust/rust-tyty-util.o \
rust/rust-tyty-call.o \
rust/rust-tyty-subst.o \
rust/rust-tyty-variance-analysis.o \
rust/rust-typecheck-context.o \
rust/rust-tyty-bounds.o \
rust/rust-hir-trait-resolve.o \
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/rust-session-manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "rust-attribute-values.h"
#include "rust-borrow-checker.h"
#include "rust-ast-validation.h"
#include "rust-tyty-variance-analysis.h"

#include "input.h"
#include "selftest.h"
Expand Down Expand Up @@ -652,6 +653,8 @@ Session::compile_crate (const char *filename)
// type resolve
Resolver::TypeResolution::Resolve (hir);

Resolver::TypeCheckContext::get ()->get_variance_analysis_ctx ().solve ();

if (saw_errors ())
return;

Expand Down
6 changes: 6 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "rust-hir-trait-reference.h"
#include "rust-autoderef.h"
#include "rust-tyty-region.h"
#include "rust-tyty-variance-analysis.h"

#include <stack>

Expand Down Expand Up @@ -233,6 +234,8 @@ class TypeCheckContext

void compute_inference_variables (bool error);

TyTy::VarianceAnalysis::CrateCtx &get_variance_analysis_ctx ();

private:
TypeCheckContext ();

Expand Down Expand Up @@ -272,6 +275,9 @@ class TypeCheckContext
std::set<HirId> querys_in_progress;
std::set<DefId> trait_queries_in_progress;

// variance analysis
TyTy::VarianceAnalysis::CrateCtx variance_analysis_ctx;

/** Used to resolve (interned) lifetime names to their bounding scope. */
class LifetimeResolver
{
Expand Down
6 changes: 6 additions & 0 deletions gcc/rust/typecheck/rust-typecheck-context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,12 @@ TypeCheckContext::compute_inference_variables (bool error)
});
}

TyTy::VarianceAnalysis::CrateCtx &
TypeCheckContext::get_variance_analysis_ctx ()
{
return variance_analysis_ctx;
}

// TypeCheckContextItem

TypeCheckContextItem::Item::Item (HIR::Function *item) : item (item) {}
Expand Down
304 changes: 304 additions & 0 deletions gcc/rust/typecheck/rust-tyty-variance-analysis-private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
#ifndef RUST_TYTY_VARIANCE_ANALYSIS_PRIVATE_H
#define RUST_TYTY_VARIANCE_ANALYSIS_PRIVATE_H

#include "rust-tyty-variance-analysis.h"

#include "rust-tyty-visitor.h"

namespace Rust {
namespace TyTy {
namespace VarianceAnalysis {

using SolutionIndex = uint32_t;

/** Term descibing variance relations. */
struct Term
{
enum Kind : uint8_t
{
CONST,
REF,
TRANSFORM,
};

Kind kind;
union
{
struct
{
Term *lhs;
Term *rhs;
} transform;
SolutionIndex ref;
Variance const_val;
};

Term () {}

Term (Variance variance) : kind (CONST), const_val (variance) {}

WARN_UNUSED_RESULT bool is_const () const { return kind == CONST; }

static Term make_ref (SolutionIndex index);

static Term make_transform (Term lhs, Term rhs);
};

/** Variance constraint of a type parameter. */
struct Constraint
{
SolutionIndex target_index;
Term *term;
};

/** Abstract variance visitor context. */
template <typename VARIANCE> class VarianceVisitorCtx
{
public:
virtual ~VarianceVisitorCtx () = default;

virtual void add_constraints_from_ty (BaseType *ty, VARIANCE variance) = 0;
virtual void add_constraints_from_region (const Region &region,
VARIANCE variance)
= 0;
void add_constraints_from_mutability (BaseType *type, Mutability mutability,
VARIANCE variance)
{
switch (mutability)
{
case Mutability::Imm:
return add_constraints_from_ty (type, variance);
case Mutability::Mut:
return add_constraints_from_ty (type, Variance::invariant ());
}
}
virtual void
add_constraints_from_generic_args (HirId ref, SubstitutionRef &subst,
VARIANCE variance, bool invariant_args)
= 0;
virtual void add_constrints_from_param (ParamType &param, VARIANCE variance)
= 0;
virtual VARIANCE contra (VARIANCE variance) = 0;
};

template <typename VARIANCE> class VisitorBase final : public TyVisitor
{
VarianceVisitorCtx<VARIANCE> &ctx;
VARIANCE variance;

public:
VisitorBase (VarianceVisitorCtx<VARIANCE> &ctx, VARIANCE variance)
: ctx (ctx), variance (variance)
{}

void visit (BoolType &type) override {}
void visit (CharType &type) override {}
void visit (IntType &type) override {}
void visit (UintType &type) override {}
void visit (FloatType &type) override {}
void visit (USizeType &type) override {}
void visit (ISizeType &type) override {}
void visit (StrType &type) override {}
void visit (NeverType &type) override {}

void visit (ClosureType &type) override {}
void visit (FnType &type) override
{
for (auto &region : type.get_used_arguments ().get_regions ())
ctx.add_constraints_from_region (region, Variance::invariant ());
}

void visit (ReferenceType &type) override
{
ctx.add_constraints_from_region (type.get_region (), variance);
ctx.add_constraints_from_mutability (type.get_base (), type.mutability (),
variance);
}
void visit (ArrayType &type) override
{
ctx.add_constraints_from_ty (type.get_element_type (), variance);
}
void visit (SliceType &type) override
{
ctx.add_constraints_from_ty (type.get_element_type (), variance);
}
void visit (PointerType &type) override
{
ctx.add_constraints_from_ty (type.get_base (), variance);
ctx.add_constraints_from_mutability (type.get_base (), type.mutability (),
variance);
}
void visit (TupleType &type) override
{
for (auto &elem : type.get_fields ())
ctx.add_constraints_from_ty (elem.get_tyty (), variance);
}
void visit (ADTType &type) override
{
ctx.add_constraints_from_generic_args (type.get_orig_ref (), type, variance,
false);
}
void visit (ProjectionType &type) override
{
ctx.add_constraints_from_generic_args (type.get_orig_ref (), type, variance,
true);
}
void visit (ParamType &type) override
{
ctx.add_constrints_from_param (type, variance);
}
void visit (FnPtr &type) override
{
auto contra = ctx.contra (variance);

for (auto &param : type.get_params ())
{
ctx.add_constraints_from_ty (param.get_tyty (), contra);
}

ctx.add_constraints_from_ty (type.get_return_type (), variance);
}

void visit (ErrorType &type) override {}

void visit (PlaceholderType &type) override { rust_unreachable (); }
void visit (InferType &type) override { rust_unreachable (); }

void visit (DynamicObjectType &type) override
{
// TODO
}
};

/** Per crate context for generic type variance analysis. */
class GenericTyPerCrateCtx
{
public: // External API
/** Add a type to context and process its variance constraints. */
void process_type (ADTType &ty);

/**
* Solve for all variance constraints and clear temporary data.
*
* Only keeps the results.
*/
void solve ();

/** Prints solution debug output. To be called after solve. */
void debug_print_solutions ();

tl::optional<SolutionIndex> lookup_type_index (HirId orig_ref);

public: // Module internal API
/** Format term tree to string. */
WARN_UNUSED_RESULT std::string to_string (const Term &term) const;

/** Formats as <type ident>`[`<param index>``]` */
WARN_UNUSED_RESULT std::string to_string (SolutionIndex index) const;

/** Evaluate a variance relation expression (term tree). */
Variance evaluate (Term *term);

std::vector<Variance> query_generic_variance (const ADTType &type);

public: // Data used by visitors.
// This whole class is private, therfore members can be public.

/** Current solutions. Initiated to bivariant. */
std::vector<Variance> solutions;

/** Constrains on solutions. Iteratively applied until fixpoint. */
std::vector<Constraint> constraints;

/** Maps TyTy::orig_ref to an index of first solution for this type. */
std::unordered_map<HirId, SolutionIndex> map_from_ty_orig_ref;
};

/** Visitor context for generic type variance analysis used for processing of a
* single type. */
class GenericTyVisitorCtx : VarianceVisitorCtx<Term>
{
using Visitor = VisitorBase<Term>;

public:
explicit GenericTyVisitorCtx (GenericTyPerCrateCtx &ctx) : ctx (ctx) {}
/** Entry point: Add a type to context and process its variance constraints.
*/
void process_type (ADTType &ty);

private:
/** Resolve a type from a TyTy::ref. */
SolutionIndex lookup_or_add_type (HirId hir_id);

/** Visit an inner type and add its constraints. */
void add_constraints_from_ty (BaseType *ty, Term variance) override;

void add_constraint (SolutionIndex index, Term term);

void add_constraints_from_region (const Region &region, Term term) override;

void add_constraints_from_generic_args (HirId ref, SubstitutionRef &subst,
Term variance,
bool invariant_args) override;

void add_constrints_from_param (ParamType &type, Term variance) override;

/** Construct a term for type in contravaraint position. */
Term contra (Term variance) override;

private:
GenericTyPerCrateCtx &ctx;

private: // Per type processing context
/** Index of the solution first **lifetime param** for the current type. */
SolutionIndex first_lifetime = 0;

/** Index of the solution first **type param** for the current type. */
SolutionIndex first_type = 0;

/** Maps type param names to index among type params. */
std::vector<std::string> param_names;
};

/** Visitor context for basic type variance analysis. */
class TyVisitorCtx : public VarianceVisitorCtx<Variance>
{
public:
using Visitor = VisitorBase<Variance>;

TyVisitorCtx (GenericTyPerCrateCtx &ctx) : ctx (ctx) {}

std::vector<Variance> collect_variances (BaseType &ty)
{
add_constraints_from_ty (&ty, Variance::covariant ());
return variances;
}

std::vector<Region> collect_regions (BaseType &ty)
{
add_constraints_from_ty (&ty, Variance::covariant ());
return regions;
}

void add_constraints_from_ty (BaseType *ty, Variance variance) override;
void add_constraints_from_region (const Region &region,
Variance variance) override;
void add_constraints_from_generic_args (HirId ref, SubstitutionRef &subst,
Variance variance,
bool invariant_args) override;
void add_constrints_from_param (ParamType &param, Variance variance) override
{}
Variance contra (Variance variance) override;

private:
GenericTyPerCrateCtx &ctx;
std::vector<Variance> variances;
std::vector<Region> regions;
};

} // namespace VarianceAnalysis

} // namespace TyTy
} // namespace Rust

#endif // RUST_TYTY_VARIANCE_ANALYSIS_PRIVATE_H
Loading

0 comments on commit 4a54a8b

Please sign in to comment.