Repository: nushell/nushell
File: crates/nu-protocol/src/ty.rs (Rust)

Code before:
            (Type::Float, Type::Number) => true,
            (Type::Int, Type::Number) => true,
            (_, Type::Any) => true,
            (Type::List(t), Type::List(u)) if t.is_subtype_of(u) => true, // List is covariant
            (Type::Record(this), Type::Record(that)) | (Type::Table(this), Type::Table(that)) => {
                is_subtype_collection(this, that)
            }
            (Type::Table(_), Type::List(_)) => true,
            _ => false,
        }
    }

    pub fn is_numeric(&self) -> bool {
        matches!(self, Type::Int | Type::Float | Type::Number)
    }

    pub fn is_list(&self) -> bool {
        matches!(self, Type::List(_))
    }

    /// Does this type represent a data structure containing values that can be addressed using 'cell paths'?
    pub fn accepts_cell_paths(&self) -> bool {
        matches!(self, Type::List(_) | Type::Record(_) | Type::Table(_))
    }

    pub fn to_shape(&self) -> SyntaxShape {
        let mk_shape = |tys: &[(String, Type)]| {
            tys.iter()
                .map(|(key, val)| (key.clone(), val.to_shape()))
                .collect()
        };

        match self {
            Type::Int => SyntaxShape::Int,
            Type::Float => SyntaxShape::Float,
            Type::Range => SyntaxShape::Range,
            Type::Bool => SyntaxShape::Boolean,
            Type::String => SyntaxShape::String,
            Type::Block => SyntaxShape::Block, // FIXME needs more accuracy
            Type::Closure => SyntaxShape::Closure(None), // FIXME needs more accuracy
            Type::CellPath => SyntaxShape::CellPath,
            Type::Duration => SyntaxShape::Duration,
            Type::Date => SyntaxShape::DateTime,
            Type::Filesize => SyntaxShape::Filesize,
            Type::List(x) => SyntaxShape::List(Box::new(x.to_shape())),
            Type::Number => SyntaxShape::Number,
            Type::Nothing => SyntaxShape::Nothing,
            Type::Record(entries) => SyntaxShape::Record(mk_shape(entries)),
            Type::Table(columns) => SyntaxShape::Table(mk_shape(columns)),
            Type::Any => SyntaxShape::Any,
            Type::Error => SyntaxShape::Any,

Review comment (suggestion):
would be a good spot to improve in the future. for example, if self and other are lists of different types then we can widen to `list<any>`. it looks like you are handling this for list expressions already but it would be good to generalize it as well

Code after:
            (Type::Float, Type::Number) => true,
            (Type::Int, Type::Number) => true,
            (_, Type::Any) => true,
            (Type::List(t), Type::List(u)) if t.is_subtype_of(u) => true, // List is covariant
            (Type::Record(this), Type::Record(that)) | (Type::Table(this), Type::Table(that)) => {
                is_subtype_collection(this, that)
            }
            (Type::Table(_), Type::List(that)) if matches!(**that, Type::Any) => true,
            (Type::Table(this), Type::List(that)) => {
                matches!(that.as_ref(), Type::Record(that) if is_subtype_collection(this, that))
            }
            (Type::List(this), Type::Table(that)) => {
                matches!(this.as_ref(), Type::Record(this) if is_subtype_collection(this, that))
            }
            _ => false,
        }
    }

    /// Returns the supertype between `self` and `other`, or `Type::Any` if they're unrelated
    pub fn widen(self, other: Type) -> Type {
        if self.is_subtype_of(&other) {
            other
        } else if other.is_subtype_of(&self) {
            self
        } else {
            Type::Any
        }
    }

    pub fn is_numeric(&self) -> bool {
        matches!(self, Type::Int | Type::Float | Type::Number)
    }

    pub fn is_list(&self) -> bool {
        matches!(self, Type::List(_))
    }

    /// Does this type represent a data structure containing values that can be addressed using 'cell paths'?
    pub fn accepts_cell_paths(&self) -> bool {
        matches!(self, Type::List(_) | Type::Record(_) | Type::Table(_))
    }

    pub fn to_shape(&self) -> SyntaxShape {
        let mk_shape = |tys: &[(String, Type)]| {
            tys.iter()
                .map(|(key, val)| (key.clone(), val.to_shape()))
                .collect()
        };

        match self {
            Type::Int => SyntaxShape::Int,