Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/fingerprint/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ impl Fingerprintable for Attribute<'_> {
) {
"attr".hash(hasher);
self.name.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
4 changes: 4 additions & 0 deletions crates/fingerprint/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl Fingerprintable for FunctionCall<'_> {
) {
"fn_call".hash(hasher);
self.function.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
Expand All @@ -52,6 +53,7 @@ impl Fingerprintable for MethodCall<'_> {
"method_call".hash(hasher);
self.object.fingerprint_with_hasher(hasher, resolved_names, options);
self.method.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
Expand All @@ -68,6 +70,7 @@ impl Fingerprintable for NullSafeMethodCall<'_> {

self.object.fingerprint_with_hasher(hasher, resolved_names, options);
self.method.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
Expand All @@ -83,6 +86,7 @@ impl Fingerprintable for StaticMethodCall<'_> {
"static_method_call".hash(hasher);
self.class.fingerprint_with_hasher(hasher, resolved_names, options);
self.method.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
23 changes: 23 additions & 0 deletions crates/fingerprint/src/class_like/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use mago_syntax::ast::Class;
use mago_syntax::ast::ClassLikeConstant;
use mago_syntax::ast::ClassLikeConstantItem;
use mago_syntax::ast::ClassLikeMember;
use mago_syntax::ast::ClassLikeReference;
use mago_syntax::ast::Enum;
use mago_syntax::ast::EnumBackingTypeHint;
use mago_syntax::ast::EnumCase;
Expand Down Expand Up @@ -57,6 +58,24 @@ impl Fingerprintable for AnonymousClass<'_> {
}
}

impl Fingerprintable for ClassLikeReference<'_> {
#[inline]
fn fingerprint_with_hasher<H: std::hash::Hasher>(
&self,
hasher: &mut H,
resolved_names: &ResolvedNames,
options: &FingerprintOptions<'_>,
) {
self.name.fingerprint_with_hasher(hasher, resolved_names, options);
if let Some(arguments) = &self.generic_arguments {
"generic_args".hash(hasher);
for argument in arguments.arguments.iter() {
argument.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
}
}

impl Fingerprintable for Extends<'_> {
#[inline]
fn fingerprint_with_hasher<H: std::hash::Hasher>(
Expand Down Expand Up @@ -475,6 +494,7 @@ impl Fingerprintable for Method<'_> {
"by_ref".hash(hasher);
}
self.name.fingerprint_with_hasher(hasher, resolved_names, options);
self.generic_parameters.fingerprint_with_hasher(hasher, resolved_names, options);
self.parameter_list.fingerprint_with_hasher(hasher, resolved_names, options);
self.return_type_hint.fingerprint_with_hasher(hasher, resolved_names, options);

Expand Down Expand Up @@ -525,6 +545,7 @@ impl Fingerprintable for Class<'_> {
}
crate::modifier::fingerprint_modifiers(self.modifiers.iter(), hasher, resolved_names, options);
self.name.fingerprint_with_hasher(hasher, resolved_names, options);
self.generic_parameters.fingerprint_with_hasher(hasher, resolved_names, options);
self.extends.fingerprint_with_hasher(hasher, resolved_names, options);
self.implements.fingerprint_with_hasher(hasher, resolved_names, options);
for member in &self.members {
Expand Down Expand Up @@ -553,6 +574,7 @@ impl Fingerprintable for Interface<'_> {
attribute_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
self.name.fingerprint_with_hasher(hasher, resolved_names, options);
self.generic_parameters.fingerprint_with_hasher(hasher, resolved_names, options);
self.extends.fingerprint_with_hasher(hasher, resolved_names, options);
for member in &self.members {
member.fingerprint_with_hasher(hasher, resolved_names, options);
Expand Down Expand Up @@ -580,6 +602,7 @@ impl Fingerprintable for Trait<'_> {
attribute_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
self.name.fingerprint_with_hasher(hasher, resolved_names, options);
self.generic_parameters.fingerprint_with_hasher(hasher, resolved_names, options);
for member in &self.members {
member.fingerprint_with_hasher(hasher, resolved_names, options);
}
Expand Down
3 changes: 3 additions & 0 deletions crates/fingerprint/src/function_like/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ impl Fingerprintable for Closure<'_> {
}
self.r#static.is_some().hash(hasher);
self.ampersand.is_some().hash(hasher);
self.generic_parameters.fingerprint_with_hasher(hasher, resolved_names, options);
self.parameter_list.fingerprint_with_hasher(hasher, resolved_names, options);
self.use_clause.fingerprint_with_hasher(hasher, resolved_names, options);
self.return_type_hint.fingerprint_with_hasher(hasher, resolved_names, options);
Expand Down Expand Up @@ -88,6 +89,7 @@ impl Fingerprintable for Function<'_> {
}
self.ampersand.is_some().hash(hasher);
self.name.fingerprint_with_hasher(hasher, resolved_names, options);
self.generic_parameters.fingerprint_with_hasher(hasher, resolved_names, options);
self.parameter_list.fingerprint_with_hasher(hasher, resolved_names, options);
self.return_type_hint.fingerprint_with_hasher(hasher, resolved_names, options);

Expand All @@ -111,6 +113,7 @@ impl Fingerprintable for ArrowFunction<'_> {
}
self.r#static.is_some().hash(hasher);
self.ampersand.is_some().hash(hasher);
self.generic_parameters.fingerprint_with_hasher(hasher, resolved_names, options);
self.parameter_list.fingerprint_with_hasher(hasher, resolved_names, options);
self.return_type_hint.fingerprint_with_hasher(hasher, resolved_names, options);
self.expression.fingerprint_with_hasher(hasher, resolved_names, options);
Expand Down
84 changes: 84 additions & 0 deletions crates/fingerprint/src/generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::hash::Hash;

use mago_names::ResolvedNames;
use mago_syntax::ast::GenericArgumentList;
use mago_syntax::ast::GenericParameter;
use mago_syntax::ast::GenericParameterList;
use mago_syntax::ast::GenericVariance;
use mago_syntax::ast::Turbofish;

use crate::Fingerprintable;
use crate::FingerprintOptions;

impl Fingerprintable for GenericParameterList<'_> {
#[inline]
fn fingerprint_with_hasher<H: std::hash::Hasher>(
&self,
hasher: &mut H,
resolved_names: &ResolvedNames,
options: &FingerprintOptions<'_>,
) {
"generic_param_list".hash(hasher);
(self.parameters.as_slice().len() as u32).hash(hasher);
for parameter in self.parameters.iter() {
parameter.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
}

impl Fingerprintable for GenericParameter<'_> {
#[inline]
fn fingerprint_with_hasher<H: std::hash::Hasher>(
&self,
hasher: &mut H,
resolved_names: &ResolvedNames,
options: &FingerprintOptions<'_>,
) {
match self.variance {
Some(GenericVariance::Covariant(_)) => "covariant".hash(hasher),
Some(GenericVariance::Contravariant(_)) => "contravariant".hash(hasher),
None => "invariant".hash(hasher),
}
self.name.value.hash(hasher);
if let Some(bound) = &self.bound {
"bound".hash(hasher);
bound.hint.fingerprint_with_hasher(hasher, resolved_names, options);
}
if let Some(default) = &self.default {
"default".hash(hasher);
default.hint.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
}

impl Fingerprintable for GenericArgumentList<'_> {
#[inline]
fn fingerprint_with_hasher<H: std::hash::Hasher>(
&self,
hasher: &mut H,
resolved_names: &ResolvedNames,
options: &FingerprintOptions<'_>,
) {
"generic_arg_list".hash(hasher);
(self.arguments.as_slice().len() as u32).hash(hasher);
for argument in self.arguments.iter() {
argument.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
}

impl Fingerprintable for Turbofish<'_> {
#[inline]
fn fingerprint_with_hasher<H: std::hash::Hasher>(
&self,
hasher: &mut H,
resolved_names: &ResolvedNames,
options: &FingerprintOptions<'_>,
) {
"turbofish".hash(hasher);
(self.arguments.as_slice().len() as u32).hash(hasher);
for argument in self.arguments.iter() {
argument.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
}
1 change: 1 addition & 0 deletions crates/fingerprint/src/instantiation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ impl Fingerprintable for Instantiation<'_> {
) {
"new".hash(hasher);
self.class.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
1 change: 1 addition & 0 deletions crates/fingerprint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod declare;
pub mod echo;
pub mod expression;
pub mod function_like;
pub mod generic;
pub mod global;
pub mod goto;
pub mod halt_compiler;
Expand Down
3 changes: 3 additions & 0 deletions crates/fingerprint/src/partial_application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl Fingerprintable for FunctionPartialApplication<'_> {
) {
"fn_partial".hash(hasher);
self.function.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
Expand All @@ -51,6 +52,7 @@ impl Fingerprintable for MethodPartialApplication<'_> {
"method_partial".hash(hasher);
self.object.fingerprint_with_hasher(hasher, resolved_names, options);
self.method.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
Expand All @@ -66,6 +68,7 @@ impl Fingerprintable for StaticMethodPartialApplication<'_> {
"static_method_partial".hash(hasher);
self.class.fingerprint_with_hasher(hasher, resolved_names, options);
self.method.fingerprint_with_hasher(hasher, resolved_names, options);
self.turbofish.fingerprint_with_hasher(hasher, resolved_names, options);
self.argument_list.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
7 changes: 7 additions & 0 deletions crates/fingerprint/src/type_hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ impl Fingerprintable for Hint<'_> {
Hint::Nullable(n) => n.fingerprint_with_hasher(hasher, resolved_names, options),
Hint::Union(u) => u.fingerprint_with_hasher(hasher, resolved_names, options),
Hint::Intersection(i) => i.fingerprint_with_hasher(hasher, resolved_names, options),
Hint::Generic(g) => {
"generic".hash(hasher);
g.base.fingerprint_with_hasher(hasher, resolved_names, options);
for argument in g.arguments.arguments.iter() {
argument.fingerprint_with_hasher(hasher, resolved_names, options);
}
}
Hint::Null(_) => "null".hash(hasher),
Hint::True(_) => "true".hash(hasher),
Hint::False(_) => "false".hash(hasher),
Expand Down
48 changes: 42 additions & 6 deletions crates/formatter/src/internal/format/call_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,39 @@ pub(super) fn print_call_like_node<'arena>(
// format the callee-like expression
let mut parts = match node {
CallLikeNode::Call(c) => match c {
Call::Function(c) => vec![in f.arena; c.function.format(f)],
Call::StaticMethod(c) => vec![in f.arena; c.class.format(f), Document::String("::"), c.method.format(f)],
Call::Function(c) => {
let mut parts = vec![in f.arena; c.function.format(f)];
if let Some(turbofish) = &c.turbofish {
parts.push(turbofish.format(f));
}
parts
}
Call::StaticMethod(c) => {
let mut parts =
vec![in f.arena; c.class.format(f), Document::String("::"), c.method.format(f)];
if let Some(turbofish) = &c.turbofish {
parts.push(turbofish.format(f));
}
parts
}
_ => {
return print_access_call_node(f, c);
}
},
CallLikeNode::Instantiation(i) => vec![in f.arena; i.new.format(f), Document::space(), i.class.format(f)],
CallLikeNode::Attribute(a) => vec![in f.arena; a.name.format(f)],
CallLikeNode::Instantiation(i) => {
let mut parts = vec![in f.arena; i.new.format(f), Document::space(), i.class.format(f)];
if let Some(turbofish) = &i.turbofish {
parts.push(turbofish.format(f));
}
parts
}
CallLikeNode::Attribute(a) => {
let mut parts = vec![in f.arena; a.name.format(f)];
if let Some(turbofish) = &a.turbofish {
parts.push(turbofish.format(f));
}
parts
}
CallLikeNode::DieConstruct(d) => vec![in f.arena; d.die.format(f)],
CallLikeNode::ExitConstruct(e) => vec![in f.arena; e.exit.format(f)],
};
Expand All @@ -130,13 +155,20 @@ pub(super) fn print_call_like_node<'arena>(
}

fn print_access_call_node<'arena>(f: &mut FormatterState<'_, 'arena>, node: &'arena Call<'arena>) -> Document<'arena> {
let (base, operator, operator_str, selector) = match node {
Call::Method(method_call) => (&method_call.object, method_call.arrow, "->", &method_call.method),
let (base, operator, operator_str, selector, turbofish) = match node {
Call::Method(method_call) => (
&method_call.object,
method_call.arrow,
"->",
&method_call.method,
method_call.turbofish.as_ref(),
),
Call::NullSafeMethod(null_safe_method_call) => (
&null_safe_method_call.object,
null_safe_method_call.question_mark_arrow,
"?->",
&null_safe_method_call.method,
null_safe_method_call.turbofish.as_ref(),
),
#[allow(clippy::unreachable)]
_ => unreachable!(),
Expand All @@ -147,6 +179,8 @@ fn print_access_call_node<'arena>(f: &mut FormatterState<'_, 'arena>, node: &'ar
|| (f.settings.preserve_breaking_member_access_chain
&& misc::has_new_line_in_range(f.source_text, base_span.end.offset, operator.start.offset));

let turbofish_doc = turbofish.map(|t| t.format(f)).unwrap_or_else(Document::empty);

if should_break {
Document::Group(Group::new(vec![
in f.arena;
Expand All @@ -156,6 +190,7 @@ fn print_access_call_node<'arena>(f: &mut FormatterState<'_, 'arena>, node: &'ar
Document::Line(Line::hard()),
format_access_operator(f, operator, operator_str),
selector.format(f),
turbofish_doc,
print_call_arguments(f, CallLikeNode::Call(node)),
]),
]))
Expand All @@ -165,6 +200,7 @@ fn print_access_call_node<'arena>(f: &mut FormatterState<'_, 'arena>, node: &'ar
base.format(f),
format_access_operator(f, operator, operator_str),
selector.format(f),
turbofish_doc,
print_call_arguments(f, CallLikeNode::Call(node)),
]))
}
Expand Down
Loading
Loading